hdu 4571 Travel in time(SPFA+DP)

Travel in time

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1009    Accepted Submission(s): 205


Problem Description
  Bob gets tired of playing games, leaves Alice, and travels to Changsha alone. Yuelu Mountain, Orange Island, Window of the World, the Provincial Museum etc...are scenic spots Bob wants to visit. However, his time is very limited, he can’t visit them all.
  Assuming that there are N scenic spots in Changsha, Bob defines a satisfaction value Si to each spot. If he visits this spot, his total satisfaction value will plus Si. Bob hopes that within the limited time T, he can start at spot S, visit some spots selectively, and finally stop at spot E, so that the total satisfaction value can be as large as possible. It's obvious that visiting the spot will also cost some time, suppose that it takes C i units of time to visit spot i ( 0 <= i < N ).
  Always remember, Bob can choose to pass by a spot without visiting it (including S and E), maybe he just want to walk shorter distance for saving time.
  Bob also has a special need which is that he will only visit the spot whose satisfaction value is strictly larger than that of which he visited last time. For example, if he has visited a spot whose satisfaction value is 50, he would only visit spot whose satisfaction value is 51 or more then. The paths between the spots are bi-directional, of course.
 

Input
  The first line is an integer W, which is the number of testing cases, and the W sets of data are following.
  The first line of each test data contains five integers: N M T S E. N represents the number of spots, 1 < N < 100; M represents the number of paths, 0 < M < 1000; T represents the time limitation, 0 < T <= 300; S means the spot Bob starts from. E indicates the end spot. (0 <= S, E < N)
  The second line of the test data contains N integers C i ( 0 <= C i <= T ), which means the cost of time if Bob visits the spot i.
  The third line also has N integers, which means the satisfaction value Si that can be obtained by visiting the spot i ( 0 <= S i < 100 ).
  The next M lines, each line contains three integers u v L, means there is a bi-directional path between spot u and v and it takes L units of time to walk from u to v or from v to u. (0 <= u, v < N, 0 <= L <= T)
 

Output
  Output case number in the first line (formatted as the sample output).
  The second line contains an integer, which is the greatest satisfaction value.
If Bob can’t reach spot E in T units of time, you should output just a “0” (without quotation marks).
 

Sample Input
  
  
1 4 4 22 0 3 1 1 1 1 5 7 9 12 0 1 10 1 3 10 0 2 10 2 3 10
 

Sample Output
  
  
Case #1: 21
 

Source
 

Recommend
zhoujiaqi2010
题意:
给定N个点,每个点有一个停留所需的时间,和停留能够获得的满意度,有M条边,每条边代表着两个点走动所需的时间,现在问在规定的T时间内从指定的一点S到E能够获得的最大的满意度是多少?要求停留的点的满意度要依次上升。
思路:
开始的想法是只在满意度小的到满意度大的建边。后来发现有问题。因为可以从满意度大的经过满意度小的而不访问。最终还是选择了SPFA+DP。用SPFA来更新dp值。dp[i][j]表示到了i点用了j时间时的最大满意度。k为满意度比i大且与i有边相连(直接或间接)的点。那么dp[k][j-c[k]]=max(dp[k][j-c[k]],dp[i][j]+s[k])。
所以先做一次floyd计算出任意两点的最短距离。因为一个点如果不访问的话可以当边处理。为了处理方便加一个虚拟的起点和虚拟的终点。不这么处理的话。起点要分为走或不走讨论。终点也是。然后用SPFA更新dp值就行了。
#include <iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int INF=0x3f3f3f3f;
int dp[110][310],vis[110][310],c[110],s[110],dis[110][110];
int n,m,u,v,l,sx,ex,sx1,ex1,t;//sx,ex为真正的起点和终点。sx1,ex1为虚拟的起点和终点
struct node
{
    int p,t;//p记录位置。t记录时间
    node(int a=0,int b=0)
    {
        p=a,t=b;
    }
};
queue<node> q;
void floyd()
{
    int i,j,k;
    for(k=0; k<n; k++)
        for(i=0; i<n; i++)
            for(j=0; j<n; j++)
                if(dis[i][k]+dis[k][j]<dis[i][j])
                    dis[i][j]=dis[i][k]+dis[k][j];
}
void spfa()
{
    int i;
    memset(vis,0,sizeof vis);
    memset(dp,0,sizeof dp);
    node tt;
    int tp;
    while(!q.empty())
        q.pop();
    q.push(node(sx1,0));//先把虚拟起点入队
    vis[sx1][0]=1;
    while(!q.empty())
    {
        tt=q.front();
        q.pop();
        vis[tt.p][tt.t]=0;
        for(i=0; i<n; i++)
        {
            if(dis[tt.p][i]>=INF||tt.p==i)
                continue;
            tp=tt.t+c[i]+dis[tt.p][i];
            if(tp<=t&&(s[tt.p]<s[i]||i==ex1))
            {
                if(dp[i][tp]<dp[tt.p][tt.t]+s[i])
                {
                    dp[i][tp]=dp[tt.p][tt.t]+s[i];
                    if(!vis[i][tp])
                    {
                        q.push(node(i,tp));
                        vis[i][tp]=1;
                    }
                }
            }
        }
    }
}
int main()
{
    int w,i,j,ans,cas=1;
    scanf("%d",&w);
    while(w--)
    {
        memset(dis,0x3f,sizeof dis);
        scanf("%d%d%d%d%d",&n,&m,&t,&sx,&ex);
        for(i=0; i<n; i++)
            dis[i][i]=0;
        for(i=0; i<n; i++)
            scanf("%d",c+i);
        for(i=0; i<n; i++)
            scanf("%d",s+i);
        for(i=0; i<m; i++)
        {
            scanf("%d%d%d",&u,&v,&l);
            if(dis[u][v]>l)
                dis[u][v]=dis[v][u]=l;
        }
        floyd();
        sx1=n,ex1=n+1;//对虚拟起点终点的处理
        c[sx1]=s[sx1]=0;
        c[ex1]=s[ex1]=0;
        dis[sx1][sx]=0;
        dis[ex][ex1]=0;
        for(i=0; i<n; i++)
        {
            dis[sx1][i]=dis[sx][i];
            dis[i][ex1]=dis[i][ex];
        }
        n+=2;
        spfa();
        ans=0;
        for(i=0; i<=t; i++)
            ans=max(ans,dp[ex1][i]);
        printf("Case #%d:\n",cas++);
        printf("%d\n",ans);
    }
    return 0;
}
DP做法要高效许多。状态表示都一样。还是floyd预处理。然后对满足值排序。然后DP。
详细见代码:
#include <iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
int dp[110][310],dis[110][110];
int n,m,u,v,l,sx,ex,t;
struct node
{
    int id,c,s;
} p[110];
bool cmp(node a,node b)
{
    return a.s<b.s;
}
void floyd()
{
    int i,j,k;
    for(k=0; k<n; k++)
        for(i=0; i<n; i++)
            for(j=0; j<n; j++)
                if(dis[i][k]+dis[k][j]<dis[i][j])
                    dis[i][j]=dis[i][k]+dis[k][j];
}
int main()
{
    int w,i,j,k,tt,p1,p2,ans,cas=1;
    scanf("%d",&w);
    while(w--)
    {
        memset(dis,0x3f,sizeof dis);
        memset(dp,-1,sizeof dp);
        scanf("%d%d%d%d%d",&n,&m,&t,&sx,&ex);
        for(i=0; i<n; i++)
            dis[i][i]=0;
        for(i=0; i<n; i++)
        {
            scanf("%d",&p[i].c);
            p[i].id=i;
        }
        for(i=0; i<n; i++)
            scanf("%d",&p[i].s);
        for(i=0; i<m; i++)
        {
            scanf("%d%d%d",&u,&v,&l);
            if(dis[u][v]>l)
                dis[u][v]=dis[v][u]=l;
        }
        floyd();
        if(dis[sx][ex]>=t)
        {
            printf("Case #%d:\n",cas++);
            printf("0\n");
            continue;
        }
        dp[sx][0]=0;
        sort(p,p+n,cmp);//按满足值排序。必须先排序。不然wa。不知道为嘛。
        for(i=0; i<n; i++)//初始化为不经过起点直接访问某一点的满足值
        {
            tt=dis[sx][p[i].id]+p[i].c;
            if(tt<=t)
                dp[p[i].id][tt]=dp[sx][0]+p[i].s;
        }
        for(j=0; j<n; j++)
        {
            for(i=0; i<=t; i++)//嵌套顺序必须这样
            {
                p1=p[j].id;
                if(dp[p1][i]==-1)//状态无效
                    continue;
                tt=i+dis[p1][ex];
                if(tt<=t&&dp[p1][i]>dp[ex][tt])//直接到终点但不访问终点
                    dp[ex][tt]=dp[p1][i];
                for(k=j+1; k<n; k++)
                {
                    p2=p[k].id;
                    if(p[j].s>=p[k].s)
                        continue;
                    tt=i+dis[p1][p2]+p[k].c;
                    if(tt<=t&&dp[p2][tt]<dp[p1][i]+p[k].s)
                        dp[p2][tt]=dp[p1][i]+p[k].s;
                }
            }
        }
        ans=0;
        for(i=0; i<=t; i++)
            ans=max(ans,dp[ex][i]);
        printf("Case #%d:\n",cas++);
        printf("%d\n",ans);
    }
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值