题目分析: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;
}
*/