hdu3033 I love sneakers! && hdu3535 AreYouBusy (组合背包)

hdu3033 题目要求与普通的组合背包(每组至多选一个)有所区别,而本题目的话,每组至少选一个,

那么如何保证每组至少选一个呢,问题就在初始化的问题还有状态转移的问题了

if(f[i][l-br[i].b[j]]!=-1 && f[i][l]<f[i][l-br[i].b[j]]+br[i].c[j]) //从当前组再多选一个
                        f[i][l]=f[i][l-br[i].b[j]]+br[i].c[j];

 if(f[i-1][l-br[i].b[j]]!=-1 && f[i][l]<f[i-1][l-br[i].b[j]]+br[i].c[j]) //在上一组的状态下,选当前组的一个
                        f[i][l]=f[i-1][l-br[i].b[j]]+br[i].c[j];

就上面这段关键的代码

 在某一状态存在的情况下(不等于-1),找出三种状态中最大的,赋值给f[i][j] .由于开始时所有f[i][j](i!=0)都为-1,所以更新时一定会从f[0][]开始,而此时就可保证当i=1时,f[i][j]中所有值不为-1的状态一定装了品牌1的某个物品。而当i>1时,
       要想得到 最初 的f[i][j],一定是从已经放有前i-1个品牌的某个状态得到的,而更新最初 的f[i][j] 也一定会用到i品牌的某
       个产品(都可由状态转移方程可知)。
       总之,保证每一类品牌 至少放一件产品是通过赋初值,条件判断,状态转移三方面实现的

 

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int n,m,k;
__int64 f[11][10010];
int num[11];
struct brand
{
    int b[101],c[101];
}br[11];
int main()
{
    while(scanf("%d %d %d",&n,&m,&k)==3)
    {
        int a;
        memset(num,0,sizeof(num));
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a);
            a;
            scanf("%d %d",&br[a].b[num[a]],&br[a].c[num[a]]);
            num[a]++;
        }
        memset(f,-1,sizeof(f));
        for(int i=0;i<=m;i++)
            f[0][i]=0;
        for(int i=1;i<=k;i++)
        {
            for(int j=0;j<num[i];j++)
            {
                for(int l=m;l>=0;l--)
                {
                    if(l<br[i].b[j])
                        continue;
                    if(f[i][l-br[i].b[j]]!=-1 && f[i][l]<f[i][l-br[i].b[j]]+br[i].c[j])
                        f[i][l]=f[i][l-br[i].b[j]]+br[i].c[j];
                    if(f[i-1][l-br[i].b[j]]!=-1 && f[i][l]<f[i-1][l-br[i].b[j]]+br[i].c[j])
                        f[i][l]=f[i-1][l-br[i].b[j]]+br[i].c[j];
                }
            }
        }
        if(f[k][m]<0)puts("Impossible");
        else printf("%I64d\n",f[k][m]);
    }
    return 0;
}

 

 hdu3535 理解了上面3033之后,这道题目其实也差不多,问题就出在赋初值的问题上了,对了每组至少选一个的情况我们已经知道了,但对于,任意选还有至多选一个的情况,初值当然是复制前一组的状态了,可是,如果不复制前一组的状态,后面的状态转移应该怎么处理,我怎么想也想不透

#include<iostream>
#include<algorithm>
#define maxn 101
#define inf 99999999
using namespace std;
struct object
{
	int c,g;
};
struct sett
{
	int k,s;
	object w[110]; 
}set[110];
int T,n,m,dp[110][maxn];
int main()
{
	while(scanf("%d %d",&n,&T)==2)
	{
		for(int i=1;i<=n;i++)
			for(int j=0;j<=T;j++)
				dp[i][j]=-inf;
		for(int i=1;i<=n;i++)
		{
			scanf("%d %d",&set[i].k,&set[i].s);
			for(int j=0;j<set[i].k;j++)
				scanf("%d %d",&set[i].w[j].c,&set[i].w[j].g);
		}
		for(int i=0;i<=T;i++)
			dp[0][i]=0;
		for(int i=1;i<=n;i++)
		{
			switch(set[i].s)
			{
			case 0:  
				     for(int j=0;j<set[i].k;j++)	
						 for(int t=T;t>=set[i].w[j].c;t--)
						 { 
			                 int v=set[i].w[j].c,cost=set[i].w[j].g;
							 int last=dp[i-1][t-v]+cost;
							 int cur=dp[i][t-v]+cost;
							 dp[i][t]=max(last,max(dp[i][t],cur));
						  }
					 break;
			case 1:
				     for(int j=0;j<=T;j++)
						 dp[i][j]=dp[i-1][j];
				     for(int j=0;j<set[i].k;j++)
						 for(int t=T;t>=set[i].w[j].c;t--)
						 {
							 int v=set[i].w[j].c,cost=set[i].w[j].g;
							 int last=dp[i-1][t-v]+cost;
						//	 dp[i][t]=max(dp[i][t],max(dp[i-1][t],last));
							 dp[i][t]=max(dp[i][t],last);//要么不选,要么从上一组的状态,在当前组选一个
						 }
				break;
			case 2: 
				     for(int j=0;j<=T;j++)
						 dp[i][j]=dp[i-1][j];
				     for(int j=0;j<set[i].k;j++)
						 for(int t=T;t>=set[i].w[j].c;t--)
						 {
							 int v=set[i].w[j].c,cost=set[i].w[j].g;
							 int cur=dp[i][t-v]+cost;
							 int last=dp[i-1][t-v]+cost;
						//	 dp[i][t]=max(dp[i-1][t],max(dp[i][t],max(cur,last)));
							 dp[i][t]=max(dp[i][t],max(last,cur));//比上一种情况多了一种选择, 就是可以从当前组继续多选择一个
						 }
				break;
			}
		}
		if(dp[n][T]<0)
			puts("-1");
		else 
		printf("%d\n",dp[n][T]);
	}
	return 0;
}

 

 

 


 

posted @ 2011-11-24 14:56  枕边梦  阅读(470)  评论(0编辑  收藏  举报