NOI2006:金明的预算方案

题目链接:http://www.rqnoj.cn/Status_Show.asp?SID=744089

这题纠结了两三天,主要是主件与附件之间的关系,然后选择问题让人纠结。我们可以将主件与对应的附件进行分组,对每个分组,我们有如下几种选择方式,都不选,只选主件,选主件与一个附件,选主件与多个附件,根据题意,每个分组最多有四种情况,这里可以直接枚举,这几种选择是互不相容的,这样就转化为了分组背包问题。那么接下来编程就相对容易的多了。

分组背包的动规方程:f(k ,v) = max{ f(k-1 ,v) , f(k-1 , v -c[i]) + w[i] , 物品i属于组k} ,其中f(k ,v)表示背包容量为v,从前k中选择若干件物品获得最大值。其实这个题目直接是有依赖的背包问题,一般先转化成对应的组,变成分组背包问题,对于每个组可以进行一次01背包问题。

代码如下:

#include 
#include 
#include 
#include 
#include 
using namespace std ;

const int maxn = 3205 ;

struct Node
{
	int p ;
	int c ;
	int w ;
	int in ;
};

int dp[65][maxn] ;
deque v1[65];
Node pack_node[65][65] ;

int m ;
int n ;
int num ;

void input();
void work() ;
void init() ;

int main()
{
	work()   ;
	return 0 ;
}

void work()
{

	int i ;
	int v ;
	int k ;

	for(i = 0 ; i < 65 ; i ++)
		v1[i].clear() ;

	memset(dp , 0 , sizeof(dp)) ;
	memset(pack_node , 0 ,sizeof(pack_node)) ;

	//freopen("data.in" , "r" , stdin) ;

	input() ;
	init() ;

	for(i = 1 ; i <= num ; i ++)
	{
		for( v = m ; v >= 0 ; v--)
		{
			dp[i][v] = dp[i-1][v] ;

			for(k = 0 ; v >= pack_node[i][k].c && k < 4 ; k ++)
			{
				if(dp[i][v] < dp[i-1][v - pack_node[i][k].c] + pack_node[i][k].w)
				{
					dp[i][v] = dp[i-1][v - pack_node[i][k].c] + pack_node[i][k].w ;
				}
			}
		}
	}

	printf("%d\n" , dp[num][m] * 10) ;
}
void  input()
{
	int i ;
	int j ;
	Node a ;

	scanf("%d%d" , &m , &n) ;
	m = m / 10 ;
	num = 0 ;

	for(i = 1 ; i <= n ; i ++)
	{
		scanf("%d%d%d" ,&a.c , &a.w , &a.p ) ;
		a.in  = i ;

		a.c = a.c / 10 ;

		if(a.p==0)
			v1[++num].push_front(a) ;

		else
		{
			for( j = 1 ; j <=num ; j ++)
				if(v1[j][0].in == a.p)
					break ;

			v1[j].push_back(a) ;
		}
	}
}

void init()
{
	int i ;
	int len ;
	for(i = 1 ; i <= num ; i ++)
	{
		len = v1[i].size() ;

		if(len>=1)
		{
				pack_node[i][0].c = v1[i][0].c ;
				pack_node[i][0].w = v1[i][0].c * v1[i][0].w ;

		}
		if(len>=2)
		{
			pack_node[i][1].c = pack_node[i][0].c + v1[i][1].c ;
			pack_node[i][1].w = pack_node[i][0].w + v1[i][1].c * v1[i][1].w ;
		}

		if(len==3)
		{
			pack_node[i][2].c = pack_node[i][0].c + v1[i][2].c ;
			pack_node[i][2].w = pack_node[i][0].w + v1[i][2].c * v1[i][2].w ;
			pack_node[i][3].c = pack_node[i][1].c + v1[i][2].c ;
			pack_node[i][3].w = pack_node[i][1].w + v1[i][2].c * v1[i][2].w ;
		}
	}
}


你可能感兴趣的:(动规)