题目:
http://acm.hdu.edu.cn/showproblem.php?pid=4571
题意:
有n个景点,互相之间有一些路,每条路都有耗时,游玩每个景点也有一个耗时,游玩每个景点之后会获得一个满意度,现在要从给定的s景点走到e景点,要求在t时间内获得最大的满意度,且游玩当前景点能够获得的满意度必须大于前一个景点时才能游玩。
思路:
因为游玩的下一个景点的满意度一定大于当前景点,所以大大简化了这道题,各景点之间的游玩顺序一定是绝对的,所有就从TSP简化成了单向的dp,只要判断每个景点是否游玩就行了,所以就是01背包,只要提前floyd预处理所有点之间的最短距离,然后背包dp就行了。还有因为给定了起点和终点,所以预处理每个点的起始值时耗时是g[i][s],并且最后的结果也是所有点每个时间加上g[i][e]也就是走回e点是最终耗时,这样的话就不用特判s,e点了,它们本身到起始/终止点的耗时是0.
代码:
#define N 112
int n,m,s,e,maxx;
int flag,sum,ave,ans,res,len,ans1,ans2;
int g[N][N],a[N];
int dp[N][5*N];
struct node
{
int x,y,r;
friend bool operator < (node a, node b)
{
return a.r < b.r;
}
}tn[N];
void init(int n)
{
memset(g,0x3f,sizeof(g));
for(int i=0;i<n;i++)
g[i][i] = 0;
}
void floyd(int n)
{
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
g[i][j] = min(g[i][j],g[i][k]+g[k][j]);
}
int main()
{
int T,cas,i,j,k,x,y,z,t;
scanf("%d",&T);
cas=0;
while(T--)
{
scanf("%d%d%d%d%d",&n,&m,&maxx,&s,&e);
sum=0;
for(i=0;i<n;i++)
{
scanf("%d",&tn[i].x);
tn[i].y=i;
}
for(i=0;i<n;i++)
scanf("%d",&tn[i].r);
sort(tn,tn+n);
for(i=0;i<n;i++)
a[tn[i].y] = i;
init(n);
for(i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&z);
g[a[x]][a[y]]=g[a[y]][a[x]]=min(z,g[a[x]][a[y]]);
}
floyd(n);
s=a[s];e=a[e];
memset(dp,-1,sizeof(dp));
for(i=0;i<n;i++)
for(j=tn[i].x+g[i][s];j<=maxx;j++)
dp[i][j] = tn[i].r;
for(i=0;i<n;i++)
for(j=0;j<i;j++)
if(tn[i].r>tn[j].r)
for(k=g[i][j]+tn[i].x;k<=maxx;k++)
if(dp[j][k-g[i][j]-tn[i].x]!=-1)
dp[i][k] = max(dp[i][k],dp[j][k-g[i][j]-tn[i].x]+tn[i].r);
res=0;
for(i=0;i<n;i++)
for(j=0;j+g[i][e]<=maxx;j++)
res=max(res,dp[i][j]);
printf("Case #%d:\n%d\n",++cas,res);
}
return 0;
}