hdu 3535 AreYouBusy(分组背包的变形---各种分组背包)

题目分析:0代表每组内的job至少取一件;1代表最多取一件;2代表可以自由取,就相当于对这一组内的job实行01背包......

注意:  1. One job can be done only once.开始没注意到这句话,还以为每组内的每个job可以做多次....囧,,,

             2.这个题花了我一天多的时间,最后看别人的解题报告才过的,,,,

             3.应该先做  hdu  3033的,这个相对于这个简单一些

             4.这个貌似不能压缩空间.....我开始压缩空间做的,一直错,样例都过不了


/*
该题要用分组背包做,这里就是要怎样处理0必须选,1最多选一个,2任意选的问题;
这里我们就开个二维数组;f[i][j],i表示第组,j表示时间;当该组为0时,我们在
该组的选择可以来自上一组的结果,也可以来自该组的结果;
如果为1那么结果只能依赖上一组的结果,如果依赖本组那么就会造成该组会多选;
为2是那就是一个01背包;
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<memory.h>
using namespace std;
struct node{
    int c,g;
}arr[1000];
int dp[1000][1000];
int main()
{
	int n,t,m,s;
	while(scanf("%d %d",&n,&t)!=EOF)
	{
		memset(dp,-1,sizeof(dp));
		memset(dp[0],0,sizeof(dp[0]));
		for(int x=1;x<=n;x++)
		{
		    scanf("%d %d",&m,&s);
		   // memset(dp,0,sizeof(dp));****不要再犯这样的低级错误
		    for(int i=1;i<=m;i++)
				scanf("%d %d",&arr[i].c,&arr[i].g);
		   
			if(s==0)//每组内.至少取一件,我们在该组的选择可以来自上一组的结果.也可以来自该组的结果;
			{
				 for(int i=1;i<=m;i++)       // for(int i=0;i<=t;i++)
					 for(int k=t;k>=arr[i].c;k--)  // for(int k=1;k<=m;k++)
					 {
						 if(dp[x][k-arr[i].c]!=-1)
							 dp[x][k]=max(dp[x][k],dp[x][k-arr[i].c]+arr[i].g);
//如果dp[i][k-arr[i].c]存在,则表示i组已经取过了,就相当与在去过的基础上再取,即,至少一个
						 if(dp[x-1][k-arr[i].c]!=-1)
						   dp[x][k]=max(dp[x][k],dp[x-1][k-arr[i].c]+arr[i].g);//确保取一个
					 }
			}
			else if(s==1)//每组至多取一件,就是分组背包的原形.
			{//只能依赖上一组的结果,如果依赖本组那么就会造成该组会多选
               for(int k=1;k<=m;k++)//for(int i=t;i>=0;i--)
				   for(int i=t;i>=0;i--)//for(int k=1;k<=m;k++)
				   {
					   dp[x][i]=max(dp[x][i],dp[x-1][i]);
					   if(i>=arr[k].c && dp[x-1][i-arr[k].c]!=-1)
					       dp[x][i]=max(dp[x][i],dp[x-1][i-arr[k].c]+arr[k].g);
				   }
			}
			else//每组内的,可以取任意件,相对于对每一组内的每一件,进行01背包
			{
				for(int k=0;k<=t;k++)
					dp[x][k]=dp[x-1][k];
               for(int k=1;k<=m;k++)
				   for(int i=t;i>=arr[k].c;i--)
					   if(dp[x][i-arr[k].c]!=-1)
					     dp[x][i]=max(dp[x][i],dp[x][i-arr[k].c]+arr[k].g);
			}
	   }
		/*if(dp[n][t]==0)
			printf("-1\n");
		else*/
	     printf("%d\n",dp[n][t]);
	}
	system("pause");
	return 0;
}

/***************************
//有错,压缩空间
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<memory.h>
using namespace std;
struct node{
    int c,g;
}arr[1000];
int dp[1000000];
int main()
{
	int n,t,m,s;
	while(scanf("%d %d",&n,&t)!=EOF)
	{
		memset(dp,0,sizeof(dp));
		for(int x=1;x<=n;x++)
		{
		    scanf("%d %d",&m,&s);
		   // memset(dp,0,sizeof(dp));****不要再犯这样的低级错误
		    for(int i=1;i<=m;i++)
				scanf("%d %d",&arr[i].c,&arr[i].g);
		   
			if(s==0)//每组内.至少取一件,我们在该组的选择可以来自上一组的结果.也可以来自该组的结果;
			{
				   for(int i=1;i<=m;i++)       // for(int i=0;i<=t;i++)
					   for(int k=t;k>=arr[i].c;k--)  // for(int k=1;k<=m;k++)
						   dp[k]=max(dp[k],dp[k-arr[i].c]+arr[i].g);
			}
			else if(s==1)//每组至多去一件,就是分组背包的原形.
			{//只能依赖上一组的结果,如果依赖本组那么就会造成该组会多选
               for(int i=t;i>=0;i--)
				   for(int k=1;k<=m;k++)
					   if(i-arr[k].c>=0)
					       dp[i]=max(dp[i],dp[i-arr[k].c]+arr[k].g);
			}
			else//每组内的,可以取任意件,相对于对每一组内的每一件,进行01背包
			{
               for(int k=1;k<=m;k++)
				   for(int i=t;i>=arr[k].c;i--)
					   dp[i]=max(dp[i],dp[i-arr[k].c]+arr[k].g);
			}
	   }
		if(dp[t]==0)
			printf("-1\n");
		else
	        printf("%d\n",dp[t]);
	}
	system("pause");
	return 0;
}*/


/***************比人的代码

个细节不懂,谁知道的话帮个忙,留个言~
三种背包,每组至少、至多取一个或随意取多少
注释在代码中
?
#include<cstdio>
#include<cstring>
int dp[110][110];
int max(int a,int b)
{
    return a>b?a:b;
}
int main()
{
    int n,T,i,j,k,m,s,w,v;
    while(scanf("%d%d",&n,&T)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&m,&s);
            if(s==0)//至少选一个
            {
                for(j=0;j<=T;j++)
                    dp[i][j]=-1;//保证下面会有一个被选中
                for(j=1;j<=m;j++)
                {
                    scanf("%d%d",&w,&v);
                    for(k=T;k>=w;k--)
                    {
                        //下面这两句话为什么一换就错啊,不懂了。。。。
                        if(dp[i][k-w]!=-1)     dp[i][k]=max(dp[i][k],dp[i][k-w]+v);//如果dp[i][k-w]存在,则表示i组已经取过了,就相当与在去过的基础上再取,即,至少一个
                        if(dp[i-1][k-w]!=-1)        dp[i][k]=max(dp[i-1][k-w]+v,dp[i][k]);//保证一定取一个
                    }
                }
            }
            if(s==1)//至多选一个
            {
                for(j=0;j<=T;j++)
                    dp[i][j]=dp[i-1][j];
                for(j=1;j<=m;j++)
                {
                    scanf("%d%d",&w,&v);
                    for(k=T;k>=w;k--)
                    {
                        if(dp[i-1][k-w]!=-1)
                            dp[i][k]=max(dp[i][k],dp[i-1][k-w]+v);
                    }
                }
            }
            if(s==2)//随意选
            {
                for(j=0;j<=T;j++)
                    dp[i][j]=dp[i-1][j];
                for(j=1;j<=m;j++)
                {
                    scanf("%d%d",&w,&v);
                    for(k=T;k>=w;k--)
                    {
                        if(dp[i][k-w]!=-1)
                            dp[i][k]=max(dp[i][k],dp[i][k-w]+v);
                    }
                }
            }
        }
        int ans=-1;
        for(i=0;i<=T;i++)
        {
            if(dp[n][i]>ans)
                ans=dp[n][i];
        }
        printf("%d\n",ans);
    }
    return 0;
}
  
 
View Code
 
分类: 动态规划
标签: 背包
绿色通道:好文要顶关注我收藏该文与我联系 
Because Of You
关注 - 1
粉丝 - 5
+加关注
0 0
(请您对文章做出评价)
« 博主前一篇:关于分组背包
» 博主后一篇:zstu 1032 拆分物品 再01背包
posted @ 2011-11-19 15:00 Because Of You Views(48) Comments(0) Edit 收藏

*/

/*
该题要用分组背包做,这里就是要怎样处理0必须选,1最多选一个,2任意选的问题;
这里我们就开个二维数组;f[i][j],i表示第组,j表示时间;
当该组为0时,我们在该组的选择可以来自上一组的结果,也可以来自该组的结果;
如果为1那么结果只能依赖上一组的结果,如果依赖本组那么就会造成该组会多选;
为2是那就是一个01背包;
*/

/*http://www.haogongju.net/art/1343345
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
class node
{
    public:
    int cost,happy;
};
class Node
{
   public:
   node t[124];
   int type,N; 
};
Node T[124];
int Max( int a, int b )
{
    return a > b ? a : b; 
}
int DP( int n , int time )
{
    int f[124][124]; 
    memset( f , -1 , sizeof( f ) );
    memset( f[0] , 0 ,sizeof(f[0]) );
    for( int i = 1 ; i <= n ; i ++ )
   {
       switch( T[i].type )
       {
          case 0: //至少取一件,即依赖上组,一依赖本组
          for( int j = 0 ; j < T[i].N; j++ )
             for( int k = time ; k >= T[i].t[j].cost ; k-- ) 
            {
                if( f[i][k-T[i].t[j].cost]!=-1 )
                    f[i][k] = Max(f[i][k],f[i][k-T[i].t[j].cost] + T[i].t[j].happy);
                if( f[i-1][k-T[i].t[j].cost]!=-1 )
                    f[i][k] = Max(f[i][k],f[i-1][k-T[i].t[j].cost] + T[i].t[j].happy); 

            } 
            break;
            case 1://至多取一件,只依赖本组
            for( int j = 0 ; j < T[i].N; j++ )
               for( int k = time ; k >= 0 ; k-- )
               {
                   f[i][k] = Max(f[i-1][k],f[i][k]); //????
                   if( k-T[i].t[j].cost>=0&&f[i-1][k-T[i].t[j].cost] != -1 )
                      f[i][k] = Max( f[i][k],f[i-1][k-T[i].t[j].cost] + T[i].t[j].happy );
               }
               break;
           case 2://任意取,01背包
           for( int j = 0 ; j <= time ; j++)
           {
              f[i][j] = f[i-1][j];
           }
           for( int j = 0 ; j < T[i].N; j++ )
			   for( int k = time ; k >0; k-- )
               {
                 if( k-T[i].t[j].cost>=0&&f[i][k-T[i].t[j].cost]!=-1 )
                      f[i][k] = Max(f[i][k], f[i][k-T[i].t[j].cost] + T[i].t[j].happy);
              }
             break;
       } //switch
     }
     return f[n][time];
}
int main( )
{
int n , m , time, type;
while( scanf( "%d%d",&n , &time )==2 )
{
for( int i = 1 ; i <= n ; i++ )
{
scanf( "%d%d",&T[i].N, &T[i].type );
for( int j = 0 ; j < T[i].N ; j++ )
{
scanf( "%d%d",&T[i].t[j].cost , &T[i].t[j].happy );
}

}
printf("%d\n", DP( n , time )); 
}
return 0; 
}
*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值