http://acm.hdu.edu.cn/showproblem.php?pid=4341
3 10 1 1 1 1 2 2 2 2 1 3 15 9 3 10 1 1 13 1 2 2 2 2 1 3 4 7
Case 1: 3 Case 2: 7
/** hdu 4341 分组背包 题目大意: 一个人在原点(0,0)抓金子,每块金子有一个价值v和获得需要的时间t。 如果金子在一条直线上,那只能先抓近的,再抓远的。求在给定时间T下,所能获得的最大价值。 解题思路:分组背包问题。把在同一直线上的点划分为同一个组,因为分组背包问题每个组只能选一件或不选, 所以要对原先的每个点进行处理,把同一组中,后面的点的t和v的值等于它前面所有点的和 这样, 选了它就一定选择了它前面的点了 剩下就是分组背包的问题了 */ #include <stdio.h> #include <string.h> #include <algorithm> #include <iostream> using namespace std; const int maxn=205; struct note { int x,y,t,v; bool operator <(const note &other)const { if(x*other.y!=other.x*y) return x*other.y<y*other.x; return y<other.y; } }node[maxn]; int n,T; int dp[maxn*maxn],num[maxn][maxn]; int main() { int tt=0; while(~scanf("%d%d",&n,&T)) { for(int i=0;i<n;i++) { scanf("%d%d%d%d",&node[i].x,&node[i].y,&node[i].t,&node[i].v); } sort(node,node+n); int cnt=0; memset(num,0,sizeof(num)); for(int i=0;i<n;i++)///斜率相同划分为同一组 { num[cnt][++num[cnt][0]]=i; if(node[i].x*node[i+1].y==node[i].y*node[i+1].x) { node[i+1].t+=node[i].t; node[i+1].v+=node[i].v; if(i==n-1) cnt++; } else cnt++; } memset(dp,0,sizeof(dp));///分组背包 for(int i=0;i<cnt;i++) { for(int j=T;j>=0;j--) { for(int k=1;k<=num[i][0];k++) { int u=num[i][k]; if(j-node[u].t>=0) dp[j]=max(dp[j],dp[j-node[u].t]+node[u].v); } } } printf("Case %d: %d\n",++tt,dp[T]); } return 0; }
原文:http://blog.csdn.net/lvshubao1314/article/details/43524341