/*
* =====================================================================================
*
* 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 ");
}