Fork me on GitHub

HDU ACM 1224 Free DIY Tour (SPFA)

Free DIY Tour

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 2735    Accepted Submission(s): 889

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

【题目意思】题目是说给你一个有环的图,结点之间有路径,每个结点都有个兴趣值,现在给你起点,找一条路径再次回到起点,使经过的结点的兴趣值总和最大,问最大的总和是多少并且输出其路径

【解题思路】其实这题是找最长路径,因为只能从编号小的结点到达编号高的结点,所以其是有向图,所以可以将结点的兴趣值赋值到相连的边上,而转换为求最长路径的问题,因为人水,也是刚开始接触图论算法,一开始选择Dijkstra算法通过修改其中的小部分步骤去计算最长路径,提交一次WA了,后来找到了原因也就是每次当前找到的不一定是最长的路径,这点随便认真地想一下便清楚了,后来想到Bellman-Ford算法,其可以将所有的边考虑到,最终便可以计算出最长的路径,当然写代码的时候还是用回SPFA即对Bellman-Ford算法的一个优化。

为什么可以用Dellman-Ford算法而不可以用Dijsktra算法,因为Dijsktral用的是贪心的思想,每次在当前找到了最短的路径修改之后就不再考虑以后有没有更短的路径,这也是Dijsktra不能用在有负权边的原因,而Delman-Ford是到最后算法结束之后才能确定源点到当前点的最短距离,所以这也是为什么可以用在求最长路径上,而能用在求最长路径上的前提是其不能有环,而这题虽然说有环,但是好在题目说明终点的编号是(N+1)且该图是有向的。

 

  1 #include <cstdio>
  2 #include <queue>
  3 #include <cstring>
  4 
  5 using namespace std;
  6 
  7 const int NV = 104;
  8 const int NE = 2000;
  9 const int INF = 1<<30;
 10 int ne, nv, tot, max_node;
 11 bool vis[NV];
 12 int dist[NV];
 13 int pre[NV];
 14 struct Edge{
 15     int u, v, cost, next;
 16     Edge(){}
 17     Edge(int a, int c){u = a, cost = c;}
 18     Edge(int a, int b, int c, int d){u = a, v = b, cost = c, next = d;}
 19     bool operator < (const Edge& x) const
 20     {
 21         return cost < x.cost;
 22     }
 23 }edge[NE];
 24 int eh[NV];
 25 int wei[NV];
 26 
 27 void SPFA(int s = 1)
 28 {
 29     for(int i = 1; i <= nv; ++i) dist[i] = i == s ? 0 : -INF;
 30     queue<Edge> que;
 31     que.push(Edge(s, 0));
 32     vis[s] = true;
 33     while(!que.empty())
 34     {
 35         Edge tmp = que.front();
 36         int u = tmp.u;
 37         que.pop();
 38         vis[u] = false;
 39         for(int i = eh[u]; i != -1; i = edge[i].next)
 40         {
 41             int v = edge[i].v;
 42             if(dist[v] < edge[i].cost + dist[u])
 43             {
 44                 dist[v] = edge[i].cost + dist[u];
 45                 pre[v] = u;
 46                 if(!vis[v])
 47                 {
 48                     que.push(Edge(v, dist[v]));
 49                     vis[v] = true;
 50                 }
 51                 
 52             }
 53         }
 54     }
 55     return;
 56 }
 57 
 58 void addedge(int u, int v, int cost)
 59 {
 60     Edge e = Edge(u, v, cost, eh[u]);
 61     edge[tot] = e;
 62     eh[u] = tot++;
 63     return;
 64 }
 65 
 66 int main()
 67 {
 68     #ifndef ONLINE_JUDGE
 69     freopen("input.txt", "r", stdin);
 70     #endif
 71     int T;
 72     scanf("%d", &T);
 73     for(int t = 1; t <= T; ++t)
 74     {
 75         memset(vis, false, sizeof(vis));
 76         memset(eh, -1, sizeof(eh));
 77         scanf("%d", &nv);
 78         for(int i = 1; i <= nv; ++i)
 79             scanf("%d", &wei[i]);
 80         wei[++nv] = wei[1];
 81         scanf("%d", &ne);
 82         for(int i = 0, u, v; i < ne; ++i)
 83         {
 84             scanf("%d%d", &u, &v);
 85             if(u > v) { u ^= v, v ^= u, u ^= v; }
 86             addedge(u, v, wei[v]);
 87         }
 88         SPFA();
 89         printf("CASE %d#\n", t);
 90         printf("points : %d\n", dist[nv]);
 91         printf("circuit : 1");
 92         int cnt = 0;
 93         for(int j = pre[nv]; j != 1; ++cnt, j = pre[j])
 94             eh[cnt] = j;
 95          for(int i = cnt-1; i >= 0; --i)
 96              printf("->%d", eh[i]);
 97         printf("->1\n"); 
 98         if(t != T) printf("\n"); 
 99     }
100     return 0;
101 }

 

 

posted @ 2013-07-31 15:56  Gifur  阅读(668)  评论(0编辑  收藏  举报
TOP