voip
风的方向
厚德致远,博学敦行!
posts - 52,comments - 21,trackbacks - 0
               在别人眼里轻而易举的的事情落在自己身上可能比登天还要难!!
                0-1背包问题:给定n中物品和一个背包。物品i的重量是wi,价值为vi,背包的容量为c。问如何选择装入背包中的武平,使得装入背包中的物品价值最大?
               书上有一行行的算式,证明最优子结构性质和构造递归关系。我没怎么看明白最优子结构,但是我能看懂递归关系式!!我记得当时老师叫我们的时候我自己想了好几天才想明白这个递归式,但是始终觉得有点虚,借此我再写一下!
               设数组m(i,j)代表背包容量为j,可选物品为i,i+1,..n时的最优解(这里的最优解指的是选择方案,并非正真的最优值),显然m(1,c)是0-1背包问题的解(这里是书上的错误,应该是m[1]中的最大值!!我后来才发现的。。)。这种定义虽然比较拗口,但是还是可以接受的,其实我们也可以这么定义m[i][j],代表背包容量为j,当前选择物品为a[i]时的最优解,显然m数组中第n行的最大值是0-1背包问题的解!!

第一种定义的递归式如下:
                                               1
   m[i][j]=max{m[i+1][j],m[i+1][j-wi]+vi}  j>=wi;    m[i][j]=m(i+1,j)   0<=j<wi

第二种定义的递归式如下:
                              0                  1
   m[i][j]=max{m[i-1][j],m[i-1][j-wi]+vi}    j>=wi;    m[i][j]=m(i-1,j)   0<=j<wi

代码如下:
#include<stdio.h>
#include
<iostream>
#include
<string.h>
using namespace std;

int max(int x,int y)
{
    
if(x>y)
        
return x;
    
return y;
}


int min(int x,int y)
{
    
if(x>y)
        
return y;
    
return x;
}


template 
<class Type>     
void Knapsack(Type *v,int *w,int c,int n,Type m[][20])//构造m,最优取舍方案函数!!
{
    
int i,j;
    
int jMax=min(w[n]-1,c);

    
for(j=0;j<=jMax;j++)
        m[n][j]
=0;

    
for(j=w[n];j<=c;j++)
        m[n][j]
=v[n];

    
for(i=n-1;i>=1;i--)
    
{
        jMax
=min(w[i]-1,c);

        
for(j=0;j<jMax;j++)
            m[i][j]
=m[i+1][j];

        
for(j=w[i];j<=c;j++)
            m[i][j]
=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);
    }


/*    m[1][c]=m[2][c];
    if(c>=w[1])
        m[1][c]=max(m[1][c],m[2][c-w[1]]+v[1]);
*/
//这里是书上的一个错误,并不是m[1][c]就是0-1背包问题的解,事实上m[1]上的所有解都有可能!!
    
//所以还是应该把m[1]上的所有最优构造都算出来,然后去最大值
}


template 
<class Type>                            //构造x数组函数
void Traceback(Type m[][20],int *w,int c,int n,int x[])
{
    
int i;
    
for(i=1;i<n;i++)
    
{
        
if(m[i][c]==m[i+1][c])
            x[i]
=0;
        
else
        
{
            x[i]
=1;
            c
-=w[i];
        }

    }


    x[n]
=(m[n][c])?1:0;
}

int main()
{
    
int w[10],v[10],x[10],m[20][20],c,n,max,c0;
    
int i,j;

    
while(scanf("%d",&n)!=EOF)
    
{
        max
=0;
        memset(m,
0,sizeof(m));
        
for(i=1;i<=n;i++)
        
{
            scanf(
"%d %d",&w[i],&v[i]);
        }

        scanf(
"%d",&c);

        Knapsack(v,w,c,n,m);    
//构造最优取舍方案
        
        
for(i=1;i<=c;i++)
        
{
            
if(m[1][i]>max)
            
{
                max
=m[1][i];
                c0
=i;
            }

        }

        Traceback(m,w,c0,n,x);        
//构造x数组
        
        printf(
"最优矩阵如下:\n");
        
for(i=1;i<=n;i++)
        
{
            
for(j=0;j<=c;j++)
                printf(
"%d ",m[i][j]);
            printf(
"\n");
        }

        
        printf(
"方案如下:\n");
        
for(i=1;i<=n;i++)
            printf(
"%d ",x[i]);
        printf(
"\n");
    }

    
return 0;
}

运行结果如下:

    
               第二种递归思路下的代码和运行过程我就不写,就初始化和递归次序不同!!
               我一个同学经常跟我说,以后自己有孩子,一个赚了1000给我花100,一个赚了10000给我花200,我还是跟着赚1000的吧!!其实问题不在别人,而在自己,努力就成!!!我受益匪浅。。。
posted on 2010-09-11 16:32 jince 阅读(1820) 评论(0)  编辑 收藏 引用 所属分类: 算法设计与分析

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


哈哈哈哈哈哈