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