01背包问题
2011-09-21 20:31
357 查看
(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");
}
/*
* =====================================================================================
*
* 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");
}