0-1背包问题(回溯法)
题目描述
有n个物品,第i个物品重量为wi,价值为vi,现有一背包容量为C,要求把物品装入背包得到最大价值,并且要求出这些选取的物品。 要求用回溯法求解。
输入
多组测试数据,请处理到文件尾,一个整数表示物品的数量n,后一行有n个整数,代表价值,再后一行有n个整数,代表重量,最后有一个整数C代表背包容量,1<=n<=15,1<=vi<=30,1<=wi<=30,1<=C<=80。
输出
背包的最大总价值和所选取的物品,如果选取的方案有多种,请输出字典序最小的那种方案,每组测试数据应输出一行,在这里字典序最小的意思是,我们假设存在两种不同方案S,T所能得到的总价值相同且是最大的,对于方案S种选取|S|种物品,方案T选取|T|种物品,对于i=1,2…j-1,我们有si = ti,但sj < tj,则方案的S的字典序比方案T的字典序要小。由于没有使用special judge,所以如果选取得方案是S,请按照从小到大的顺序输出方案S中的物品下标。
样例输入 Copy
5
6 3 6 5 4
2 2 4 6 5
8
样例输出 Copy
15 1 2 3
#include<bits/stdc++.h>
using namespace std;
struct thing{
int w,v;
double p;
int id;
};
thing th[105];
int C;
int n;
double cw;
double cv;
double bestv;
int bestx[105];
int x[105];
int cmp(thing &a,thing &b){
return a.p>b.p;
}
double bound(int i){
int left=C-cw;
int b=cv;
while(i<n&&th[i].w<=left)
{
left-=th[i].w;
b+=th[i].v;
i++;
}
if(i<n)
b+=left*th[i].p;
return b;
}
void backtrack(int i){
if(i+1>n)
{
bestv=cv;
for(int j=0;j<n;j++)
bestx[j]=x[j];
return;
}
if(cw+th[i].w<=C)
{
x[i]=1;
cw+=th[i].w;
cv+=th[i].v;
backtrack(i+1);
x[i]=0;
cw-=th[i].w;
cv-=th[i].v;
}
if(bound(i+1)>bestv)
{
backtrack(i+1);
}
}
int main()
{
int i;
while(cin>>n){
//init();
memset(x,0,sizeof(x));
memset(bestx,0,sizeof(bestx));
cv=cw=bestv=0;
for(i=0;i<n;++i)
cin>>th[i].v;
for(i=0;i<n;++i){
cin>>th[i].w;
th[i].id=i+1;
th[i].p=th[i].v*1.0/th[i].w;
}
cin>>C;
sort(th,th+n,cmp);
backtrack(0);
int s[105];
int ans=0;
for(i=0;i<n;++i)
{
if(bestx[i])
s[ans++]=th[i].id;
}
sort(s,s+ans);
cout<<bestv;
for(i=0;i<ans;++i)
cout<<" "<<s[i];
cout<<endl;
}
return 0;
}
旅行售货员(TSP)
题目描述
有若干个城市,任何两个城市之间的距离都是确定的,现要求一旅行商从某城市出发必须经过每一个城市且只在一个城市逗留一次,最后回到出发的城市,问如何事先确定一条最短的线路以保证路径最短?
输入
输入两个整数n,m分别代表城市数量,边数量,2<=n<=8,n-1<=m<=2*n
接下来m行每行输入有3个整数x,y,z代表x和y城市之间有一条长为z的路,保证输入的图是连通的,旅行商总是从1城市出发。
输出
要求求出最短的路径,和该路径的长度,如果不存在这样的路径你只需要输出-1。
样例输入 Copy
4 6
1 2 30
1 3 6
1 4 4
2 3 5
2 4 10
3 4 20
样例输出 Copy
1 3 2 4 1
25
#include<bits/stdc++.h>
using namespace std;
const double Max=100000;
int n,m;
int x[105];//当前解
int bestx[105];//最优解
int bestc=-1;//最优费用
int cc;//当前费用
int g[105][105];
int NoEdge=-1;
int sum;
void backstrack(int t){
if(t==n){
if(g[x[n-1]][x[n]]!=NoEdge&&g[x[n]][1]!=NoEdge&&(bestc==NoEdge||cc+g[x[n-1]][x[n]]+g[x[n]][1]<bestc)){
for(int j=1;j<=n;j++){
bestx[j]=x[j];
}
sum++;
bestc=cc+g[x[n-1]][x[n]]+g[x[n]][1];
}
}else{
for(int j=t;j<=n;j++){
if(g[x[t-1]][x[j]]!=-1&&(bestc==-1||cc+g[x[t-1]][x[j]]<bestc)){
swap(x[t],x[j]);
cc+=g[x[t-1]][x[t]];
backstrack(t+1);
cc-=g[x[t-1]][x[t]];
swap(x[t],x[j]);
}
}
}
}
int main()
{
while(cin>>n>>m){
sum=0;
//for(int i=1;i<=n;++i){
// for(int j=1;j<=n;++j){
//a[i][j]=a[j][i]=Max;
//}
//}
memset(g,-1,sizeof(g));
for(int i=1;i<=m;++i){
int x,y,z;
cin>>x>>y>>z;
g[x][y]=z;
g[y][x]=z;
}
for(int i=1;i<=n;++i){
x[i]=i;
}
cc=0;
backstrack(2);
//double ans=tsp();
if(sum==0){
cout<<-1<<endl;
return 0;
}
else{
for(int i=1;i<=n;++i){
cout<<bestx[i]<<" ";
}
cout<<bestx[1]<<endl;
cout<<bestc<<endl;
}
}
return 0;
}