您的位置:首页 > 其它

ZJU2041 Gangsters - 动态规划 阶段选择

2008-04-08 16:32 246 查看
题目大意:

N个小偷先后来到一家饭店偷东西。饭店的门有K+1种[0-K]不同的打开程度,0表示关闭。如果门在Ti时刻的打开程度刚好等于第i个小偷的勇敢程度Si,那么小偷就会进去偷走Pi价值的物品;否则这个小偷就会直接走掉。饭店的门一个单位时间最多可以改变1的打开程度,如果有一个人适当地控制门的打开程度,问N个小偷最多能偷走多少东西。(N<=100,K<=100,T<=30000)

分析:

阶段很明显的动态规划

最朴素的想法是用数组dp[t][k]表示t时刻门的打开程度是k,能偷走的最大价值。这个想法是正确的,但是由于时间T很大,效率很低。

可以按照小偷到来的时间排序一下。用dp[i]表示第i个小偷到来并且进入饭店,能偷走的最大价值。那么状态转移方程可以如下描述:

dp[i] = 0 // 若小偷i的勇敢程度大于他到来的时间( thief[i].s > thief[i].t )
= max{ thief[i].p ,
thief[i].p + dp[j] // 若小偷j的勇敢程度和小偷i的勇敢程度之差不超过他们到来的时间间隔
// if( (thief[i].t - thief[j].t) >= abs(thief[i].s - thief[j].s )
}


很容易写出程序。题目也很典型,主要是要考虑用时间作为阶段还是用小偷作为阶段。

许多题目都是这样,选择正确的阶段表示方法很重要,减少了许多不必要的计算。

-------------------------------------------------------------------------------------------

/*
ZJU2041 Gangsters
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define clr(a) memset(a,0,sizeof(a))

#define N 105

typedef struct{
int t,s,p;
}Thief;

Thief a
;
int f
;

int cmp(const void *a,const void *b){
return ((Thief*)a)->t - ((Thief*)b)->t;
}
inline int abs(int a){
return a>0?a:-a;
}
inline int max(int a,int b){
return a>b?a:b;
}

int main()
{
int i,j,k,m,n,T;
int ans;

scanf("%d",&T);
while(T--){
//input
scanf("%d%d%d",&n,&m,&k); //n thiefs, m states, k times
for(i=0;i<n;i++) scanf("%d",&a[i].t);
for(i=0;i<n;i++) scanf("%d",&a[i].p);
for(i=0;i<n;i++) scanf("%d",&a[i].s);

//sort
qsort(a,n,sizeof(Thief),cmp);

//DP
//f[i]表示第i个thief到来且进入商店获得的最大价值
//f[i]=max{a[i].p, f[j]+a[i].p (ai.t-a[j].t>=abs(a[i].s-a[j].s))}
clr(f);
ans=0;
for(i=0;i<n;i++){
if(a[i].s>a[i].t) continue;
f[i]=a[i].p;

for(j=0;j<i;j++)
if((a[i].t-a[j].t)>=abs(a[i].s-a[j].s)){
f[i]=max(f[i],f[j]+a[i].p);
}
ans=max(ans,f[i]);
}

//output
printf("%d/n",ans);
if(T) puts("");
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: