【HDU4571 Travel in time】二维多状态spfa

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4571

题目大意:小A去小B家,图中有多个点,每个点有一个两个值c,w,表示拜访该点消费的时间为c,同时获得的幸福指数为w,问你在时间T范围内,要求走走最短的路程,并且如果先拜访u再拜访v,那么v点的幸福指数大于u才可以去拜访,求小A能够获得的最大的幸福指数是多少。

 

解题思路:这题巨坑,开始用优先队列+bfs,无奈的TLE,后来又改成spfa,WA到死。

     本题要求路程最短,可以先用floyd预处理出最短路,然后再在这个最短路的基础上进行spfa,spfa过程中每个点都有T个状态,dis[x][t]表示在时间t时刻x点获得的最大幸福指数是多少。思路是没错的,可怜的我WA的蛋疼了。最后发现从起点和终点这两个点是两个超级大bug,为什么这么说呢,你看假若直接从起点出发那么处理的必不是拜访起点,而你处理起点下一个点的时候表示的又是拜访了起点,这样是错的。对于终点,不是一定到要拜访终点,也可以只需到达即可。这两个bug太让人伤心了。怎么处理呢?建立两个虚拟节点(一个超级起点,一个超级终点),则两个起点的作用分别是拜访和不拜访,两个终点的作用也是如此。如果考虑到了这两点,基本问题就出来了。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 #include <queue>
  5 #include <cstring>
  6 using namespace std;
  7 
  8 const int maxn=110;
  9 const int oo=0x3fffffff;
 10 int S[maxn], C[maxn];
 11 int mp[maxn], visit[maxn][3*maxn];
 12 int map[maxn][maxn], cap[maxn][maxn], dis[maxn][3*maxn];
 13 int n, m, V, T, st, sd, ss, dd;
 14 
 15 struct node
 16 {
 17     int u, t;
 18 };
 19 
 20 void floyd()
 21 {
 22     ss=n, dd=n+1, S[dd]=0;
 23     for(int k=0; k<n; k++)
 24         for(int i=0; i<n; i++)
 25             for(int j=0; j<n; j++)
 26                 if(map[i][j]>map[i][k]+map[k][j]) map[i][j]=map[i][k]+map[k][j];
 27 
 28     for(int i=0; i<n; i++)
 29         for(int j=i+1; j<n; j++)
 30         {
 31             if(map[i][j]!=oo)
 32             {
 33                 if(S[i]<S[j]) cap[i][j]=map[i][j]+C[j];
 34                 if(S[j]<S[i]) cap[j][i]=map[i][j]+C[i];
 35             }
 36         }
 37     cap[ss][st]=C[st];
 38     for(int i=0; i<n; i++)
 39         if(i!=st&&map[st][i]!=oo) cap[ss][i]=map[st][i]+C[i];
 40     for(int i=0; i<n; i++)
 41         if(i!=sd&&map[i][sd]!=oo) cap[i][dd]=map[i][sd];
 42 
 43 }
 44 
 45 
 46 int spfa()
 47 {
 48     queue<node>q;
 49     for(int i=0; i<=n+1; i++)
 50         for(int j=0; j<=V; j++) dis[i][j]=-oo, visit[i][j]=0;
 51     node s, p;
 52     s.u=ss, s.t=0;
 53     q.push(s);
 54     dis[ss][0]=0;
 55     visit[ss][0]=1;
 56     while(!q.empty())
 57     {
 58         p=q.front();
 59         q.pop();
 60         visit[p.u][p.t]=0;
 61         for(int i=0; i<=n+1; i++)
 62         {
 63             if(p.u!=i&&cap[p.u][i]!=oo)
 64             {
 65                 int tp=p.t+cap[p.u][i];
 66                 if(tp<=V&&dis[i][tp]<dis[p.u][p.t]+S[i])
 67                 {
 68                     dis[i][tp]=dis[p.u][p.t]+S[i];
 69                     s.u=i, s.t=tp;
 70                     if(!visit[s.u][s.t]) visit[s.u][s.t]=1,q.push(s);
 71                 }
 72             }
 73         }
 74     }
 75     int maxx=0;
 76     for(int i=0; i<=V; i++)
 77     {
 78         maxx=max(maxx,dis[sd][i]);
 79         maxx=max(maxx,dis[dd][i]);
 80     }
 81     return maxx;
 82 }
 83 
 84 int main()
 85 {
 86     cin >> T;
 87     for(int tcase=1; tcase<=T; tcase++)
 88     {
 89         scanf("%d%d%d%d%d",&n,&m,&V,&st,&sd);
 90         for(int i=0; i<=n+1; i++)
 91             for(int j=0; j<=n+1; j++)
 92             {
 93                   map[i][j]=oo, cap[i][j]=oo;
 94                   if(i==j) map[i][j]=cap[i][j]=0;
 95             }
 96         for(int i=0; i<n; i++) scanf("%d",C+i);
 97         for(int i=0; i<n; i++) scanf("%d",S+i);
 98         while(m--)
 99         {
100             int u, v, val;
101             scanf("%d%d%d",&u,&v,&val);
102             map[u][v]=min(map[u][v],val);
103             map[v][u]=min(map[v][u],val);
104         }
105         floyd();
106         int ans=spfa();
107         printf("Case #%d:\n%d\n",tcase,ans);
108     }
109     return 0;
110 }
View Code

 

 

posted @ 2013-06-06 18:49  Mr. Ant  阅读(532)  评论(0编辑  收藏  举报