求解0/1背包问题
穷举法
问题描述:
问题求解:对于n个物品,容量为W的背包问题。
<1>先采用求幂集的方法求出所有的物品组合。
<2>对于每一种组合,计算组合中物品的总重量sumw,总价值sumv。
<3>对于每一种组合,如果sumw <= W ,说明该组合是一种解。比较所有解,将最佳方案保存在 maxsumw 和 maxsumv 中。输出所有解与最佳解。
#include<stdio.h>
#define Maxn 10
#define MaxSize 1000
typedef struct{ //幂集类型
int data[MaxSize][Maxn]; //data[i][0] 表示该子集的长度
int n; //幂集的个数
}pSetType;
void copy(int a[],int b[],int m){ //将a[0...m]复制到b[0...m]
int i;
for(i=0;i<=m;i++)
b[i] = a[i];
}
void pset(int n,pSetType &p){ //求1~n的幂集p
int i,j,m;
int a[Maxn];
p.data[0][0] = 0;
p.n = 1;
for(i=1;i<=n;i++){
m = p.n;
for(j=0;j<m;j++){
copy(p.data[j],a,p.data[j][0]);
a[0]++;
a[a[0]] = i;
copy(a,p.data[p.n],a[0]);
p.n++;
}
}
}
void knap(pSetType p,int w[],int v[],int W){
int i,j;
int sumw,sumv;
int maxi,maxsumw = 0,maxsumv = 0;
printf(" 序号\t选中物品\t总重量\t总价值\t能否装入\n");
for(i=0;i<p.n;i++){
printf(" %d\t",i+1);
sumw = sumv = 0;
printf("{");
for(j=1;j <= p.data[i][0];j++){
printf("%d",p.data[i][j]);
sumv += v[p.data[i][j] - 1];
sumw += w[p.data[i][j] - 1];
}
printf("}\t\t%d\t%d\t",sumw,sumv);
if(sumw<=W){
printf("能\n");
if(sumv > maxsumv){
maxsumw = sumw;
maxsumv = sumv;
maxi = i;
}
}
else
printf("否\n");
}
printf("最佳方案: ");
printf("选中物品: ");
printf("{");
for(j=1;j<=p.data[maxi][0];j++)
printf("%d",p.data[maxi][j]);
printf("},");
printf("总重量 = %d,总价值 = %d\n",maxsumw,maxsumv);
}
int main(){
int n=4,W = 7;
int w[] = {5,3,2,1};
int v[] = {4,4,3,1};
pSetType p;
pset(n,p);
printf("0/1背包的求解方案\n",n);
knap(p,w,v,W);
printf("\n");
return 0;
}
动态规划
//求解0_1背包问题
//动态规划
#include<stdio.h>
#define MaxN 20
#define MaxW 100
int knap(int f[MaxN][MaxW],int w[],int v[],int W,int n){
//动态规划求数组f[][]
int i,r;
for(i=0;i<=n;i++)
f[i][0] = 0;
for(r=0;r<=W;r++)
f[0][r] = 0;
for(i=1;i<=n;i++){
for(r=1;r<=W;r++){
if(r < w[i])
f[i][r] = f[i-1][r];
else{
if(f[i-1][r] < f[i-1][r-w[i]] + v[i])
f[i][r] = f[i-1][r-w[i]] + v[i];
else
f[i][r] = f[i-1][r];
}
}
}
return f[n][W];
}
int Traceback(int f[MaxN][MaxW],int w[],int x[],int W,int n){
int i,r=W;
int maxw = 0;
for(i=n;i>0;i--){
if(f[i][r] != f[i-1][r]){
x[i] = 1;
maxw += w[i];
r = r - maxw;
}
else
x[i] = 0;
}
return maxw;
}
void dispknap(int x[],int maxw,int maxv,int n){
int i;
printf("最佳背包方案是:\n");
for(i=0;i<=n;i++){
if(x[i] == 1)
printf("选取第%d种物品\n",i);
}
printf("总重量=%d,总价值=%d",maxw,maxv);
}
int main(){
int f[MaxN][MaxW];
int x[MaxN];
int maxv;
int maxw;
int n=5,W=10;
int w[MaxN] = {0,2,2,6,5,4};
int v[MaxN] = {0,6,3,5,4,6};
maxv = knap(f,w,v,W,n);
maxw = Traceback(f,w,x,W,n);
dispknap(x,maxw,maxv,n);
return 0;
}
回溯法
#include<stdio.h>
#define MAXN 20
int maxw;
int maxv;
int x[MAXN];
void knap(int w[],int v[],int W,int n,int i,int tw,int tv,int op[]){
int j;
if(i>n){
if(tw<W && tv>maxv){
maxv = tv;
maxw = tw;
for(j=1;j<=n;j++)
x[j] = op[j];
}
}
else{
op[i] = 1;
knap(w,v,W,n,i+1,tw+w[i],tv+v[i],op);
op[i] = 0;
knap(w,v,W,n,i+1,tw,tv,op);
}
}
void disp(int x[],int n){
int i;
printf("最佳方案是:\n");
for(i=1;i<=n;i++){
if(x[i] == 1)
printf("选取第%d个物品\n",i);
}
printf("总重量 = %d,总价值 = %d",maxw,maxv);
}
int main(){
int n=4;
int W = 7;
int op[MAXN];
int w[] = {0,5,3,2,1};
int v[] = {0,4,4,3,1};
knap(w,v,W,n,1,0,0,op);
disp(x,n);
return 0;
}
左剪枝
void knap(int w[],int v[],int W,int n,int i,int tw,int tv,int op[]){
int j;
if(i>n){
if(tw<W && tv>maxv){
maxv = tv;
maxw = tw;
for(j=1;j<=n;j++)
x[j] = op[j];
}
}
else{
if(tw+w[i] < W)
{
op[i] = 1;
knap(w,v,W,n,i+1,tw+w[i],tv+v[i],op);
}
op[i] = 0;
knap(w,v,W,n,i+1,tw,tv,op);
}
}
右剪枝
void knap(int w[],int v[],int W,int n,int i,int tw,int tv,int op[]){
int j,m;
if(i>n){
if(tw<W && tv>maxv){
maxv = tv;
maxw = tw;
for(j=1;j<=n;j++)
x[j] = op[j];
}
}
else{
if(tw+w[i] < W)
{
op[i] = 1;
knap(w,v,W,n,i+1,tw+w[i],tv+v[i],op);
}
op[i] = 0;
m=0;
for(j=0;j<i;j++)
if(op[j] == 0) m++;
if(m<=1)
knap(w,v,W,n,i+1,tw,tv,op);
}
}
#include<stdio.h>#define Maxn 10#define MaxSize 1000typedef struct{//幂集类型int data[MaxSize][Maxn];//data[i][0] 表示该子集的长度int n;//幂集的个数}pSetType;void copy(int a[],int b[],int m){//将a[0...m]复制到b[0...m]int i;for(i=0;i<=m;i++)b[i] = a[i];}void pset(int n,pSetType &p){//求1~n的幂集pint i,j,m;int a[Maxn];p.data[0][0] = 0;p.n = 1;for(i=1;i<=n;i++){m = p.n;for(j=0;j<m;j++){copy(p.data[j],a,p.data[j][0]);a[0]++;a[a[0]] = i;copy(a,p.data[p.n],a[0]);p.n++; }}}void knap(pSetType p,int w[],int v[],int W){int i,j;int sumw,sumv;int maxi,maxsumw = 0,maxsumv = 0;printf("序号\t选中物品\t总重量\t总价值\t能否装入\n");for(i=0;i<p.n;i++){printf("%d\t",i+1);sumw = sumv = 0;printf("{");for(j=1;j <= p.data[i][0];j++){printf("%d",p.data[i][j]);sumv += v[p.data[i][j] - 1];sumw += w[p.data[i][j] - 1]; }printf("}\t\t%d\t%d\t",sumw,sumv);if(sumw<=W){printf("能\n");if(sumv > maxsumv){maxsumw = sumw;maxsumv = sumv;maxi = i;} }elseprintf("否\n");} printf("最佳方案: ");printf("选中物品: ");printf("{");for(j=1;j<=p.data[maxi][0];j++)printf("%d",p.data[maxi][j]);printf("},");printf("总重量 = %d,总价值 = %d\n",maxsumw,maxsumv);}int main(){int n=4,W = 7;int w[] = {5,3,2,1};int v[] = {4,4,3,1};pSetType p;pset(n,p);printf("0/1背包的求解方案\n",n);knap(p,w,v,W);printf("\n");return 0;}
浙公网安备 33010602011771号