01背包问题

来源:互联网 发布:mysql修改端口 编辑:程序博客网 时间:2024/05/29 09:01
 
(DP)01背包问题
/*
* =====================================================================================
*
*       Filename:  Bag01.c
*
*    Description:  01背包问题
*                                      有N个物品, 重量分别为w1到wn,价值分别为v1到vn,有一个承重为C的包,问该将哪些物品放入包
*                                      中可使得包中物品的价值和最大, 设m[i][j]代表在承重为j,可供装包的物品编号为从i(包括i)
*                                      到N时的最大价值(物品的最小编号为1),则此时递推公式为
*                                      m[i][j] = max(m[i+1][j], m[i+1][j-wi] + vi) //两种情况:取物品i和不取物品i,从这两种情况中取最大值
*        Version:  1.0
*        Created:  2010年08月25日 08时59分40秒
*       Revision:  none
*       Compiler:  gcc
*
*         Author:  glq2000 (), glq2000@126.com
*        Company:  HUE ISRC
*
* =====================================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX(A,B) (((A)>(B))?(A):(B))
#define N 7     //物品个数
#define C 19    //包的承重
int w[N+1] = {0, 3, 7, 2, 4, 8, 10, 5}; //w[i]:物品i的重量, 简单起见,w[0]不使用
int v[N+1] = {0, 2, 10, 3, 5, 7, 12, 6};//v[i]:物品i的价值, 简单起见,v[0]不使用
int m[N+1][C+1];//加1的目的是为了使用方便,m[i][j]表示在承重为j,可供装包的物品编号为从i(包括i)到N时的最大价值(物品的最小编号为1)

void MaxBagValue(int (*m)[C+1], int n, int c, int *w, int *v);  //计算m[i][j]数组
void Output(int (*m)[C+1]);             //输出m[i][j]数组
void TraceBack(int (*m)[C+1]);          //求出被选择的物品的编号

int main()
{
        MaxBagValue(m, N, C, w, v);
        Output(m); printf("\n\n\n\n");
        printf("MaxBagValue: %d\n\n", m[1][C]);
        TraceBack(m);

        return 0;
}


/*
*m[i][j]表示在承重为j,可供装包的物品编号为从i(包括i)到N时的最大价值(物品的最小编号为1)
*w[i] 重量, v[i] 价值, c当前包中剩余承重, n 当前可供装包的编号为从n(包括n)到N
*/
void MaxBagValue(int (*m)[C+1], int n, int c, int *w, int *v)
{
        int i, j;
        for(j=1; j<=c; ++j)
                if(j >= w[N])
                        m[N][j] = v[N];

        for(i=n-1; i>=1; --i)
        {
                for(j=1; j<=c; ++j)
                if(j >= w[i])
                        m[i][j] = MAX(m[i+1][j], m[i+1][j-w[i]]+v[i]);
                else
                        m[i][j] = m[i+1][j];
        }
}


void Output(int (*m)[C+1])              //输出m[i][j]数组
{
        int i,j;
        for(i=1; i<=N; ++i)
        {
                printf("w[%d]=%d  ", i, w[i]);
        }
        printf("\n");
        for(i=1; i<=N; ++i)
        {
                printf("v[%d]=%d  ", i, v[i]);
        }
        printf("\n\n");

        for(i=0; i<=N; ++i)
        {
                for(j=0; j<=C; ++j)
                {
                        printf("m[%d][%d]=%d ", i, j, m[i][j]);
                }
                printf("\n\n");
        }
}


//利用m数组求出哪些编号的物品被选中了
void TraceBack(int (*m)[C+1])
{
        printf("Seletced: ");
        int i=1,j=C;
        while(j && i<=N)
        {
                if(i==N && j>0 && m[i][j]==v[i])
                {
                        printf("%d ", i);
                        j -= w[i];
                        ++i;
                }
                if(m[i][j] > m[i+1][j])
                {
                        printf("%d ", i);
                        j -= w[i];
                        ++i;
                }
                else
                        ++i;
        }
        printf("\n");
}
原创粉丝点击