• 求解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("	序号	选中物品	总重量	总价值	能否装入
    ");
    	for(i=0;i<p.n;i++){
    		printf("	%d	",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("}		%d	%d	",sumw,sumv);
    		if(sumw<=W){
    			printf("能
    ");
    			if(sumv > maxsumv){
    				maxsumw = sumw;
    				maxsumv = sumv;
    				maxi = i;
    			} 
    		}
    		else
    			printf("否
    ");
    	} 
    	printf("最佳方案: ");
    	printf("选中物品: ");
    	printf("{");
    	for(j=1;j<=p.data[maxi][0];j++)
    		printf("%d",p.data[maxi][j]);
    	printf("},");
    	printf("总重量 = %d,总价值 =  %d
    ",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);
    	knap(p,w,v,W);
    	printf("
    ");
    	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("最佳背包方案是:
    ");
    	for(i=0;i<=n;i++){
    		if(x[i] == 1)
    			printf("选取第%d种物品
    ",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("最佳方案是:
    ");
    	for(i=1;i<=n;i++){
    		if(x[i] == 1)
    			printf("选取第%d个物品
    ",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("序号 选中物品 总重量 总价值 能否装入 ");for(i=0;i<p.n;i++){printf("%d ",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("} %d %d ",sumw,sumv);if(sumw<=W){printf("能 ");if(sumv > maxsumv){maxsumw = sumw;maxsumv = sumv;maxi = i;}elseprintf("否 ");printf("最佳方案: ");printf("选中物品: ");printf("{");for(j=1;j<=p.data[maxi][0];j++)printf("%d",p.data[maxi][j]);printf("},");printf("总重量 = %d,总价值 =  %d ",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);knap(p,w,v,W);printf(" ");return 0;

  • 相关阅读:
    JavaScript之arguments对象讲解
    JavaScript之工厂方式 构造函数方式 原型方式讲解
    JavaScript之常用方法讲解
    JavaScript之引用类型讲解
    JavaScript之数据类型讲解
    JavaScript之Cookie讲解
    __cdecl __stdcall __fastcall之函数调用约定讲解
    xp/2003开关3389指令
    php源码安装常用配置参数和说明
    用yum查询想安装的软件
  • 原文地址:https://www.cnblogs.com/Hqx-curiosity/p/12147950.html
Copyright © 2020-2023  润新知