一、函数题
1.0/1背包问题 (队列式分枝限界法)
2.0/1背包问题 (优先队列分枝限界法)
二、编程题
1.子集和问题
2.八皇后问题(*)
3.0-1背包
4.工作分配问题
5.德邦国王
6.图着色问题
0/1背包问题。给定一载重量为m的背包及n个重量为wi、价值为vi的物体,1≤i≤n,要求把物体装入背包,使背包的物体价值最大。
void bound(NodeType &e); //算分枝结点e的上界
void EnQueue(NodeType e,queue&qu);//结点e进队qu
void bfs();//求0/1背包的最优解
void bound(NodeType &e) //算分枝结点e的上界
{
int i=e.i+1,sumw=e.w;
double sumv=e.v;
while((sumw+w[i]<=W)&&i<=n)
{
sumw+=w[i],sumv+=v[i];
i++;
}
if(i<=n)e.ub=sumv+(W-sumw)*v[i]/w[i];
else e.ub=sumv;
}
void EnQueue(NodeType e,queue &qu)//结点e进队qu
{
if(e.i==n)
{
if(e.v>maxv)
{
maxv=e.v;
for(int i=1;i<=n;i++)
bestx[i]=e.x[i];
}
}
else qu.push(e);
}
void bfs()//求0/1背包的最优解
{
NodeType e1,e2,e;
e.i=e.w=e.v=0;e.no=total++;
queue qu;
for(int i=1;i<=n;i++)e.x[i]=0;
bound(e);qu.push(e);
while(!qu.empty())
{
e=qu.front();qu.pop();
if(e.w+w[e.i+1]<=W)
{
e1.i=e.i+1;
e1.w=e.w+w[e1.i],e1.v=e.v+v[e1.i];
e1.no=total++;
for(int i=1;i<=n;i++)e1.x[i]=e.x[i];
e1.x[e1.i]=1;
bound(e1);EnQueue(e1,qu);
}
e2=e,e2.i++;
e2.x[e2.i]=0;e2.no=total++;
bound(e2);
if(e2.ub>maxv)EnQueue(e2,qu);
}
}
0/1背包问题。给定一载重量为m的背包及n个重量为wi、价值为vi的物体,1≤i≤n,要求把物体装入背包,使背包的物体价值最大。
void bound(NodeType &e); //计算分枝结点e的上界
void EnQueue(NodeType e,priority_queue&qu); //结点e进队qu
void bfs(); //求0/1背包的最优解
void bound(NodeType &e) //算分枝结点e的上界
{
int i=e.i+1,sumw=e.w;
double sumv=e.v;
while((sumw+w[i]<=W)&&i<=n)
{
sumw+=w[i],sumv+=v[i];
i++;
}
if(i<=n)e.ub=sumv+(W-sumw)*v[i]/w[i];
else e.ub=sumv;
}
void EnQueue(NodeType e,priority_queue &qu) //结点e进队qu
{
if(e.i==n)
{
if(e.v>maxv)
{
maxv=e.v;
for(int i=1;i<=n;i++)
bestx[i]=e.x[i];
}
}
else qu.push(e);
}
void bfs()//求0/1背包的最优解
{
NodeType e1,e2,e;
e.i=e.w=e.v=0;e.no=total++;
priority_queue qu;
for(int i=1;i<=n;i++)e.x[i]=0;
bound(e);qu.push(e);
while(!qu.empty())
{
e=qu.top();qu.pop();
if(e.w+w[e.i+1]<=W)
{
e1.i=e.i+1;
e1.w=e.w+w[e1.i],e1.v=e.v+v[e1.i];
e1.no=total++;
for(int i=1;i<=n;i++)e1.x[i]=e.x[i];
e1.x[e1.i]=1;
bound(e1);EnQueue(e1,qu);
}
e2=e,e2.i++;
e2.x[e2.i]=0;e2.no=total++;
bound(e2);
if(e2.ub>maxv)EnQueue(e2,qu);
}
}
设集合S={x1,x2,…,xn}是一个正整数集合,c是一个正整数,子集和问题判定是否存在S的一个子集S1,使S1中的元素之和为c。试设计一个解子集和问题的回溯法,并输出利用回溯法在搜索树(按输入顺序建立)中找到的第一个解。
输入数据第1行有2个正整数n和c,n表示S的大小,c是子集和的目标值。接下来的1行中,有n个正整数,表示集合S中的元素。
是子集和的目标值。接下来的1 行中,有n个正整数,表示集合S中的元素。
输出利用回溯法找到的第一个解,以空格分隔,最后一个输出的后面有空格。当问题无解时,输出“No Solution!”。
#include
using namespace std;
const int N=1e5+10;
int n,c,sum,all;
bool st[N];
int a[N];
vector v,res;
void dfs(int u)
{
if(u==n)
{cout<<"No Solution!";return;}
if(sum==c)
{
for(auto x:v)res.push_back(x);
return ;
}
for(int i=0;i>n>>c;
for(int i=0;i>a[i],all+=a[i];
if(all
在国际象棋中,皇后是最厉害的棋子,可以横走、直走,还可以斜走。棋手马克斯·贝瑟尔 1848 年提出著名的八皇后问题:即在 8 × 8 的棋盘上摆放八个皇后,使其不能互相攻击 —— 即任意两个皇后都不能处于同一行、同一列或同一条斜线上。例如:
现在我们把棋盘扩展到 n×n 的棋盘上摆放 n 个皇后,请问该怎么摆?
请编写程序,输入正整数 n,输出全部摆法(棋盘格子空白处显示句点“.”,皇后处显示字母“Q”,每两个字符之间空一格)。
正整数 n(n>0)
若问题有解,则输出全部摆法(每两种摆法之间空一行)。
若问题无解,则输出 None。
要求:试探的顺序按从上到下逐行进行,其中每一行按从左到右的逐格进行,请参看输出样例2。
#include
using namespace std;
const int N=20;
int n;
char x[N][N];
bool row[N], col[N], dg[N], udg[N];
bool flag=false;
void dfs(int u)
{
if(u==n)
{
if(flag)cout<>n;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
x[i][j] = '.';
dfs(0);
if(!flag)cout<<"None";
return 0;
}
给定n(n<=100)种物品和一个背包。物品i的重量是wi(wi<=100),价值为vi(vi<=100),背包的容量为C(C<=1000)。
应如何选择装入背包中的物品,使得装入背包中物品的总价值最大? 在选择装入背包的物品时,对每种物品i只有两个选择:装入或不装入。不能将物品i装入多次,也不能只装入部分物品i。
共有n+1行输入:
第一行为n值和c值,表示n件物品和背包容量c;
接下来的n行,每行有两个数据,分别表示第i(1≤i≤n)件物品的重量和价值。
输出装入背包中物品的最大总价值。
#include
using namespace std;
const int N=1e5+10;
int w[N],v[N],f[N];
int main()
{
int n,c;cin>>n>>c;
for(int i=1;i<=n;i++)cin>>w[i]>>v[i];
for(int i=1;i<=n;i++)
{
for(int j=c;j>=w[i];j--)
{
f[j]=max(f[j],f[j-w[i]]+v[i]);
}
}
cout<
设有n件工作分配给n个人。将工作i分配给第j个人所需的费用为cij 。 设计一个算法,对于给定的工作费用,为每一个人都分配1 件不同的工作,并使总费用达到最小。
输入数据的第一行有1 个正整数n (1≤n≤20)。接下来的n行,每行n个数,表示工作费用。
将计算出的最小总费用输出到屏幕。
#include
using namespace std;
const int N=20;
int a[N][N];
bool st[N];
vector v;
int n,res,ans=0x3f3f3f3f;
void dfs(int u)
{
if(u==n)
{ans=min(ans,res);return ;}
for(int i=0;i>n;
for(int i=0;i>a[i][j];
dfs(0);
cout<
在遥远的德邦草原,有一个古老的国度。
这里的国王有一种特殊的能力,他可以在限定次数内互换自己和某些子民的位置
现在国王需要让自己的子民排列成一个整齐的方阵接受检阅,但是他们的动作太慢了
于是国王决定用自己的能力来完成剩余的排列,从而将自己的子民排列
成能让他满意的样子。
请你帮忙计算国王最少需要瞬间移动多少次,才能将方阵变成他想要的样子。
注意国王不得移动出方阵,国王的瞬间移动方式将由输入数据给出。
N K M分别表示矩阵的大小、国王的瞬移方法数量和国王的瞬间移动限定次数
接下来 K 行 Xi Yi 表示国王可以让自己和 (X + Xi, Y + Yi)上的子民位置互换
其中 X Y 表示国王当前的位置
接下来 N 行为一个矩阵,表示当前的矩阵排列
接下来 N 行为一个矩阵,表示能让国王满意的矩阵排列
矩阵仅由(0, 1, 2)组成,其中 0 表示女性子民,1 表示男性子民, 2 表示国王
1 <= N <= 5
1 <= K <= 8
1 <= M <= 15
如果国王可以在限定次数内将矩阵变成他喜欢的样子,请你输出最小次数
反之,请你输出 -1
#include
using namespace std;
const int N=100;
int a[N],b[N],f1[N][N],f2[N][N];
int n,k,m,X,Y;
int ans=0x3f3f3f3f;
void dfs(int x,int y,int u)
{
int s=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(f1[i][j]!=f2[i][j])s++;
if(s==0){ans=min(ans,u);return ;}
if(u>ans)return ;
if(s>m-u)return ;
for(int i=0;i0&&dx<=n&&dy>0&&dy<=n)
{
swap(f1[x][y],f1[dx][dy]);
dfs(dx,dy,u+1);
swap(f1[x][y],f1[dx][dy]);
}
}
}
int main()
{
cin>>n>>k>>m;
for(int i=0;i>a[i]>>b[i];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
cin>>f1[i][j];
if(f1[i][j]==2)
X=i,Y=j;
}
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)cin>>f2[i][j];
dfs(X,Y,0);
if(ans>m)cout<<-1;
else cout<
图着色问题是一个著名的NP完全问题。给定无向图G=(V,E),问可否用K种颜色为V中的每一个顶点分配一种颜色,使得不会有两个相邻顶点具有同一种颜色?
但本题并不是要你解决这个着色问题,而是对给定的一种颜色分配,请你判断这是否是图着色问题的一个解。
输入在第一行给出3个整数V(0 对每种颜色分配方案,如果是图着色问题的一个解则输出输出格式:
Yes
,否则输出No
,每句占一行。#include