6-2 0/1背包问题(回溯法)
分数 20
全屏浏览题目
切换布局
作者 王东
单位 贵州师范学院
0/1背包问题。给定一载重量为W的背包及n个重量为wi、价值为vi的物体,1≤i≤n,要求而且重量和恰好为W具有最大的价值。
函数接口定义:
void dfs(int i,int tw,int tv,int rw,int op[]);
其中tw表示装入背包中的物品总重量,tv表示背包中物品总价值,op记录一个解向量。
裁判测试程序样例:
#include <stdio.h>#include <string.h>#include <iostream>#define MAXN 20 //最多物品数using namespace std;int n; //物品数int W; //限制重量int w[MAXN]={0}; //存放物品重量,不用下标0元素int v[MAXN]={0}; //存放物品价值,不用下标0元素int x[MAXN]; //存放最终解int maxv; //存放最优解的总价值void dfs(int i,int tw,int tv,int rw,int op[]);void dispasolution() //输出最优解{ int i; for (i=1;i<=n;i++) if (x[i]==1) printf("%d ",i); printf("\n%d %d",W,maxv);}int main(){ int i; cin>>n>>W; //输入物体个数及背包载重量 for(int i=1;i<=n;i++)//输入各物体重量及价值 cin>>w[i]>>v[i]; int op[MAXN]; //存放临时解 memset(op,0,sizeof(op)); int rw=0; for (int i=1;i<=n;i++) rw+=w[i]; dfs(1,0,0,rw,op); dispasolution(); return 0;}/* 请在这里填写答案 */
输入格式:
第一行输入背包载重量W及背包个数n,再依次输入n行,每行为背包重量wi和价值vi。
输出格式:
第一行输出输出装入背包内的物体编号(末尾有空格),第二行输出背包内的物体总重量和总价值。
输入样例1:
5 10
2 6
2 3
6 5
5 4
4 6
输出样例1:
1 2 3
10 14
void dfs(int i,int tw,int tv,int rw,int op[]) //求解0/1背包问题
{
int j;
if (i>n) //找到一个叶子结点
{ if (
tw==W && tv>maxv
) //找到一个满足条件的更优解,保存它
{ maxv=tv;
for (
j=1;j<=n;j++
) //复制最优解
x[j]=op[j];
}
}
else //尚未找完所有物品
{ if (
tw+w[i]<=W
) //左孩子结点剪枝:满足条件时才放入第i个物品
{
op[i]=1; //选取第i个物品
dfs(
i+1,tw+w[i],tv+v[i],rw-w[i],op
);
}
op[i]=0; //不选取第i个物品,回溯
if (
tw+rw>W
) //右孩子结点剪枝
dfs(
i+1,tw,tv,rw-w[i],op
);
}
}
6-3 快速排序(分治法)
分数 10
全屏浏览题目
切换布局
作者 王东
单位 贵州师范学院
快速排序(分治法)
函数接口定义:
int Partition(SqList &L,int low,int high);//实现一趟划分。void QSort(SqList &L,int low,int high);
裁判测试程序样例:
#include <iostream>#define MAXSIZE 1000using namespace std;typedef struct{ int key; char *otherinfo;}ElemType; typedef struct{ ElemType *r; int length;}SqList;int Partition(SqList &L,int low,int high);void QSort(SqList &L,int low,int high);void Create_Sq(SqList &L){ int i,n; cin>>n; //输入的值不大于 MAXSIZE for(i=1;i<=n;i++) { cin>>L.r[i].key; L.length++; }}void show(SqList L){ int i; for(i=1;i<=L.length;i++) if(i==1) cout<<L.r[i].key; else cout<<" "<<L.r[i].key;}int main(){ SqList L; L.r=new ElemType[MAXSIZE+1]; L.length=0; Create_Sq(L); QSort(L,1,L.length); show(L); return 0;}/* 请在这里填写答案 */
输入样例:
第一行输入一个数n,接下来输入n个数。
7
24 53 45 45 12 24 90
输出样例:
输出按升序排序的结果。
12 24 24 45 45 53 90
代码长度限制
16 KB
时间限制
400 ms
内存限制
int Partition(SqList &L,int low,int high)
{
int pivotkey;
L.r[0]=L.r[low];
pivotkey=L.r[low].key;
while(
low<high
)
{
while(
low<high&&L.r[high].key>=pivotkey
) --high;
L.r[low]=L.r[high];
while(
low<high&&L.r[low].key<=pivotkey
) ++low;
L.r[high]=L.r[low];
}
L.r[low]=L.r[0];
return low;
}
void QSort(SqList &L,int low,int high)
{
int pivotloc;
if(low<high)
{
pivotloc=
pivotloc= Partition(L,low,high)
;
QSort(L,low,pivotloc-1)
;
QSort(L,pivotloc+1,high)
;
}
}
void QuickSort(SqList &L)
{
QSort(L,1,L.length);
}
6-4 棋盘覆盖问题(分治法)
分数 20
全屏浏览题目
切换布局
作者 王东
单位 贵州师范学院
用分治法求解棋盘覆盖问题。有一个2k×2k(k>0)的棋盘,恰好有一个方格与其他方格不同,称之为特殊方格。现在要用如下的L型骨牌覆盖除了特殊方格外的其他全部方格,骨牌可以任意旋转,并且任何两个骨牌不能重叠。请给出一种覆盖方法。
函数接口定义:
void ChessBoard(int tr,int tc,int dr,int dc,int size);(tr,tc)表示一个象限左上角方格的坐标,(dr,dc)是特殊方格所在的坐标。size是棋盘的行数和列数。
裁判测试程序样例:
#include <iostream>#include<fstream>#include <iomanip>#define MAX 1025using namespace std;int board[MAX][MAX];int tile=1;void ChessBoard(int tr,int tc,int dr,int dc,int size);int main(){int dr,dc,size;int j,i;cin>>size;cin>>dr>>dc;ChessBoard(0,0,dr,dc,size);for(i=0;i<size;i++){ cout<<left; for(j=0;j<size;j++) { cout<<setfill(' ')<<setw(5)<<board[i][j]; } cout<<endl;}return 0;} /* 请在这里填写答案 */
输入样例:
第一行输入一个数n表示棋盘大小,第二行输入特殊方格的行列下标。
8
1 2
输出样例:
输出棋盘。
3 3 4 4 8 8 9 9
3 2 0 4 8 7 7 9
5 2 2 6 10 10 7 11
5 5 6 6 1 10 11 11
13 13 14 1 1 18 19 19
13 12 14 14 18 18 17 19
15 12 12 16 20 17 17 21
15 15 16 16 20 20 21 21
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
void ChessBoard(int tr,int tc,int dr,int dc,int size)
{ if(
size==1
) return; //递归出口
int t=tile++; //取一个L型骨,其牌号为tile
int s=size/2; //分割棋盘
//考虑左上角象限
if(
dr<tr+s&&dc<tc+s
) //特殊方格在此象限中
ChessBoard(tr,tc,dr,dc,s)
;
else //此象限中无特殊方格
{
board[tr+s-1][tc+s-1]=t
; //用t号L型骨牌覆盖右下角
ChessBoard(tr,tc,tr+s-1,tc+s-1,s)
; //将右下角作为特殊方格继续处理该象限
}
//考虑右上角象限
if(
dr<tr+s&&dc>=tc+s
)
ChessBoard(tr,tc+s,dr,dc,s)
; //特殊方格在此象限中
else //此象限中无特殊方格
{
board[tr+s-1][tc+s]=t
; //用t号L型骨牌覆盖左下角
ChessBoard(tr,tc+s,tr+s-1,tc+s,s)
; //将左下角作为特殊方格继续处理该象限
}
//处理左下角象限
if(
dr>=tr+s&&dc<tc+s
) //特殊方格在此象限中
ChessBoard(tr+s,tc,dr,dc,s)
;
else //此象限中无特殊方格
{
board[tr+s][tc+s-1]=t
; //用t号L型骨牌覆盖右上角
ChessBoard(tr+s,tc,tr+s,tc+s-1,s)
; //将右上角作为特殊方格继续处理该象限
}
//处理右下角象限
if(
dr>=tr+s&&dc>=tc+s
) //特殊方格在此象限中
ChessBoard(tr+s,tc+s,dr,dc,s)
;
else //此象限中无特殊方格
{
board[tr+s][tc+s]=t
; //用t号L型骨牌覆盖左上角
ChessBoard(tr+s,tc+s,tr+s,tc+s,s)
; //将左上角作为特殊方格继续处理该象限
}
}
6-5 求解活动安排问题(贪心法)
分数 10
全屏浏览题目
切换布局
作者 王东
单位 贵州师范学院
假设有一个需要使用某一资源的n个活动所组成的集合S,S={1,…,n}。该资源任何时刻只能被一个活动所占用,活动i有一个开始时间bi和结束时间ei(bi<ei),其执行时间为ei-bi,假设最早活动执行时间为0。
一旦某个活动开始执行,中间不能被打断,直到其执行完毕。若活动i和活动j有bi≥ej或bj≥ei,则称这两个活动兼容。
设计算法求一种最优活动安排方案,使得所有安排的活动个数最多。
函数接口定义:
void solve();
裁判测试程序样例:
#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>using namespace std;#define MAX 51//问题表示struct Action{ int b; //活动起始时间 int e; //活动结束时间 bool operator<(const Action &s) const //重载<关系函数 { return e<=s.e; //用于按活动结束时间递增排序 }};int n;Action A[MAX]; bool flag[MAX]; //标记选择的活动int Count=0; //选取的兼容活动个数void solve();int main(){ cin>>n; for (int i=0;i<n;i++) cin>>A[i].b>>A[i].e; solve(); for (int i=0;i<n;i++) if (flag[i]) { printf("[%d,%d]\n",A[i].b,A[i].e); Count++; } cout<<Count; return 0;}/* 请在这里填写答案 */
输入格式:
第一行是一个整数n,接着的n行中每一行包括两个整数b和e,其中b是一个订单开始时间,e是的结束时间。。
输出格式:
若count表示最大兼容活动集合数,先输出count行,每行为活动的开始时间和结束时间。最后输出count。
输入样例1:
11
1 4
3 5
0 6
5 7
3 8
5 9
6 10
8 11
8 12
2 13
12 15
输出样例1:
[1,4]
[5,7]
[8,11]
[12,15]
4
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
void solve() //求解最大兼容活动子集
{
memset(flag,0,sizeof(flag));//初始化为false
sort(A,A+n); //A[1..n]按活动结束时间递增排序
int preend=0; //前一个兼容活动的结束时间
for (int i=0;i<n;i++)
{ if (
A[i].b>=preend
)
{
flag[i]=true
;
preend=A[i].e
;
}
}
}
6-6 最小生成树(克鲁斯卡尔算法)
分数 10
全屏浏览题目
切换布局
作者 王东
单位 贵州师范学院
试实现克鲁斯卡尔最小生成树算法。
函数接口定义:
void Kruskal(AMGraph G);
其中 G 是基于邻接矩阵存储表示的无向图。
裁判测试程序样例:
#include <stdio.h>#define MVNum 10 #define MaxInt 32767 typedef struct{ char vexs[MVNum]; int arcs[MVNum][MVNum]; int vexnum,arcnum; }AMGraph;struct Evode{ char Head; char Tail; int lowcost;}Edge[(MVNum * (MVNum - 1)) / 2];int Vexset[MVNum];void CreateUDN(AMGraph &G);//实现细节隐藏void Kruskal(AMGraph G);int main(){ AMGraph G; CreateUDN(G); Kruskal(G); return 0;}/* 请在这里填写答案 */
输入样例:
第1行输入结点数vexnum和边数arcnum。第2行输入vexnum个字符表示结点的值,接下来依次输入arcnum行,每行输入3个值,前两个字符表示结点,后一个数表示两个结点之间边的权值。
7 9
0123456
0 1 28
0 5 10
1 2 16
1 6 14
2 3 12
3 6 18
3 4 22
4 5 25
4 6 24
输出样例:
按最小生成树的生成顺序输出每条边。
0->5
2->3
1->6
1->2
3->4
4->5
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
窗体顶端
C++ (g++)
1
#include<bits/stdc++.h>
2
using namespace std;
3
int cmp(Evode a,Evode b)
4
{
5
return a.lowcost<b.lowcost;
6
}
7
8
int find(char x)//找父亲
9
{
10
int y;
11
y = int(x)-int('0');
12
while(Vexset[y]!=y)y=Vexset[y];
13
return y;
14
}
15
16
int add(char x,char y)//判断是否为同一个父亲,不是就加到一起
17
{
18
if(find(x)==find(y))return 0;
19
else
20
{
21
int fx = find(x);
22
int fy = find(y);
23
Vexset[fx]=fy;
24
return 1;
25
}
26
}
27
28
void Kruskal(AMGraph G)
29
{
30
for(int i=0;i<G.vexnum;i++)
31
{
32
Vexset[int(G.vexs[i])-int('0')]=int(G.vexs[i])-int('0');//开始的父亲就是自己
33
}
34
35
sort(Edge,Edge+G.arcnum,cmp);//按结构体中路径长短排序
36
窗体底端
测试用例
上一题
查看上次提交
提交本题作答
下一题
#include<bits/stdc++.h>
using namespace std;
int cmp(Evode a,Evode b)
{
return a.lowcost<b.lowcost;
}
int find(char x)//找父亲
{
int y;
y = int(x)-int('0');
while(Vexset[y]!=y)y=Vexset[y];
return y;
}
int add(char x,char y)//判断是否为同一个父亲,不是就加到一起
{
if(find(x)==find(y))return 0;
else
{
int fx = find(x);
int fy = find(y);
Vexset[fx]=fy;
return 1;
}
}
void Kruskal(AMGraph G)
{
for(int i=0;i<G.vexnum;i++)
{
Vexset[int(G.vexs[i])-int('0')]=int(G.vexs[i])-int('0');//开始的父亲就是自己
}
sort(Edge,Edge+G.arcnum,cmp);//按结构体中路径长短排序
for(int i=0;i<G.arcnum;i++)
{
if(add(Edge[i].Head,Edge[i].Tail))
{
printf("%c->%c\n",Edge[i].Head,Edge[i].Tail);
}
}
}
6-7 求解最长递增子序列问题(动态规划法)
分数 10
全屏浏览题目
切换布局
作者 王东
单位 贵州师范学院
求解最长递增子序列问题。给定一个无序的整数序列a[0..n-1],求其中最长递增子序列的长度(不一定连续)。
函数接口定义:
void IncreaseOrder(int a[],int dp[],int x[][N],int n);
裁判测试程序样例:
#include<bits/stdc++.h>#include<iostream>#define N 100 using namespace std;void IncreaseOrder(int a[],int dp[],int x[][N],int n);int main(){ //dp[i]表示a[0..i]中以a[i]结尾的最长递增子序列的长度 //X[i][0..dp[i]-1]表示以a[i]结尾的最长递增子序列 int A[N],dp[N],X[N][N]; int n,i,index; cin>>n; for(i=0;i<n;i++) cin>>A[i]; IncreaseOrder(A,dp,X,n); for (index = 0, i = 1; i < n; i++) //求所有递增子序列的最大长度 if (dp[index] < dp[i]) index = i; cout<<dp[index]<<endl; for (i = 0; i < dp[index]; i++) //输出最长递增子序列 cout<<X[index][i]<<" "; return 0;}/* 请在这里填写答案 */
输入格式:
第一行为正整数n,表示序列元素个数,第二行依次输入n个数。
9
2 1 5 3 6 4 8 9 7
输出格式:
输出最长递增子序列的长度及序列。
5
2 5 6 8 9
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
void IncreaseOrder(int a[],int dp[],int x[][N],int n)
{
int i, j, k, index;
for (i = 0; i < n; i++) //依次计算a[0]~a[i]的最长递增子序列
{
dp[i] = 1;
x[i][0] = a[i];
int max = 1;
int maxindex=i; //初始化递增子序列长度的最大值
for(int j = 0;j < i;j ++) {
if ((a[j] < a[i]) && (max<dp[j]+1)){
max = dp[j]+1;
maxindex=j;
}
}
if(maxindex!=i){
dp[i] = max;
for (k = 0; k < max-1; k++) //存储最长递增子序列
x[i][k] = x[maxindex][k];
x[i][max-1]= a[i];
}
}
}
6-8 最短路径(弗洛伊德算法)
分数 10
全屏浏览题目
切换布局
作者 王东
单位 贵州师范学院
试实现弗洛伊德最短路径算法。
函数接口定义:
void ShortestPath_Floyed(AMGraph G);
其中 G 是基于邻接矩阵存储表示的有向图。
裁判测试程序样例:
#include <iostream>using namespace std;#define MaxInt 32767#define MVNum 100typedef char VerTexType; typedef int ArcType;int Path[MVNum][MVNum]; int D[MVNum][MVNum];typedef struct{ VerTexType vexs[MVNum]; ArcType arcs[MVNum][MVNum]; int vexnum,arcnum; }AMGraph;void CreateUDN(AMGraph &G);//实现细节隐藏void ShortestPath_Floyed(AMGraph G);void DisplayPath(AMGraph G , int begin ,int temp ){ if(Path[begin][temp] != -1){ DisplayPath(G , begin ,Path[begin][temp]); cout << G.vexs[Path[begin][temp]] << "->"; }}int main(){ AMGraph G; char start , destination; int num_start , num_destination; CreateUDN(G); ShortestPath_Floyed(G); cin >> start >> destination; num_start = LocateVex(G , start); num_destination = LocateVex(G , destination); DisplayPath(G , num_start , num_destination); cout << G.vexs[num_destination]<<endl; cout << D[num_start][num_destination]; return 0;}/* 请在这里填写答案 */
输入样例:
第1行输入结点数vexnum和边数arcnum。第2行输入vexnum个字符表示结点的值,接下来依次输入arcnum行,每行输入3个值,前两个字符表示结点,后一个数表示两个结点之间边的权值。最后一行输入源点及终点。
6 8
012345
0 5 100
0 2 10
0 4 30
1 2 5
2 3 50
3 5 10
4 3 20
4 5 60
0 5
输出样例:
第一行输出源点到终点的最短路径,第二行输出源点到终点的最短路径距离。
0->4->3->5
60
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
窗体顶端
C++ (g++)
1
void ShortestPath_Floyed(AMGraph G){
2
int i , j , k ;
3
for (i = 0; i < G.vexnum; ++i)
4
for(j = 0; j < G.vexnum; ++j){
5
D[i][j] =
6
G.arcs[i][j]
7
;
8
if(D[i][j] < MaxInt && i != j)
9
Path[i][j]=i
10
;
11
else Path [i][j] = -1;
12
}
13
for(k = 0; k < G.vexnum; ++k)
14
for(i = 0; i < G.vexnum; ++i)
15
for(j = 0; j < G.vexnum; ++j)
16
if(
17
D[i][k] + D[k][j]
18
< D[i][j]){
19
D[i][j] =
20
D[i][k]+D[k][j]
21
;
22
Path[i][j] =
23
Path[k][j]
24
;
25
}
26
}
窗体底端
测试用例
上一题
查看上次提交
提交本题作答
下一题
void ShortestPath_Floyed(AMGraph G){
int i , j , k ;
for (i = 0; i < G.vexnum; ++i)
for(j = 0; j < G.vexnum; ++j){
D[i][j] =
G.arcs[i][j]
;
if(D[i][j] < MaxInt && i != j)
Path[i][j]=i
;
else Path [i][j] = -1;
}
for(k = 0; k < G.vexnum; ++k)
for(i = 0; i < G.vexnum; ++i)
for(j = 0; j < G.vexnum; ++j)
if(
D[i][k] + D[k][j]
< D[i][j]){
D[i][j] =
D[i][k]+D[k][j]
;
Path[i][j] =
Path[k][j]
;
}
}
6-9 求解图的m着色问题(回溯法)
分数 10
全屏浏览题目
切换布局
作者 王东
单位 贵州师范学院
给定无向连通图G和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色。如果有一种着色法使G中每条边的两个顶点着不同颜色,则称这个图是m可着色的。图的m着色问题是对于给定图G和m种颜色,找出所有不同的着色法。
函数接口定义:
void dfs(int i);
裁判测试程序样例:
#include <stdio.h>#include <string.h>#define MAXN 20 //图最多的顶点个数int n,k,m;int a[MAXN][MAXN];int count=0; //全局变量,累计解个数int x[MAXN]; //全局变量,x[i]表示顶点i的着色bool Same(int i) //判断顶点i是否与相邻顶点存在相同的着色{ for (int j=1;j<=n;j++) if (a[i][j]==1 && x[i]==x[j]) return false; return true;}int main(){ memset(a,0,sizeof(a)); //a初始化 memset(x,0,sizeof(x)); //x初始化 int x,y; scanf("%d%d%d",&n,&k,&m); //输入n,k,m for (int j=1;j<=k;j++) { scanf("%d%d",&x,&y); //输入一条边的两个顶点 a[x][y]=1; //无向图的边对称 a[y][x]=1; } dfs(1); //从顶点1开始搜索 if (count>0) //输出结果 printf("%d",count); else printf("-1"); return 0;}/* 请在这里填写答案 */
输出格式:
程序运行结束时,将计算出的不同的着色方案数输出。如果不能着色,程序输出-1。
输入样例:
5 8 4
1 2
1 3
1 4
2 3
2 4
2 5
3 4
4 5
输出样例:
48
代码长度限制
16 KB
时间限制
400 ms
内存限制
void dfs(int i) //求解图的m着色问题
{
if (i>n)
{
count++
;
}
else
{
for (int j=1;j<=m;j++)
{
x[i]=j;
if (
Same(i)
)
dfs(i+1);
x[i]=0
;
}
}
}