PAT1018

题目链接:http://pat.zju.edu.cn/contests/pat-a-practise/1018

此题算比较难的,第一求最短路径,最短路径有多条时,要选出送出自行车最少的,当送出自行车最少的不止一个时,要选送回自行车最少的。

我的思想:首先看到题,第一反应就是Dijkstra最短路径求,这么做需要在做Dij的同时,保存每个节点的相关信息,这样一次遍历足以。为了保存相应结点信息,设计了如下的数据结构。 map<int, vector<pair<Node, vector<int>>>> info; 描述如下图:

map键值对key对应节点值,value为vector<pair<Node, vector<int>>>类型,用来存多条最短路径,Node 结点用来存collect和sent,vector<int>用来存取其中一条最短路径走过的所有节点(不包括自身)。

  

  剩下的工作就是在Dij时更新数据,在此说明下,有一点要注意的:若每个站点的perfect station = 5, 有如下最短路径序列, 2 3 6 5 1 8,第一次提交有2个case没过是因为如下思想,首先定义collect=0,走到2时,2-5=-3,代表需要从原点取3辆自行车,collect += -3, 然后, 3-5=-2,collect+=-2,以此类推,最后得collect=-5,表格如下,

2 3 6 5 1 8
-3 -5 -4 -4 -8 -5

误以为需要从原点取5个自行车就够了,其实是错的。是因为车子是从前往后送的,不能用后面的补前面的!!正确的思路是这样的,2的时候需要3个,3的时候需要5个,以此类推,在1的时候需要8个,这时候需要量达到最大,所以需要从原点取8个自行车,所以用sent值来存储collect变化序列中最小的,当sent的值为负时,就代表需要从原点取自行车。

接下来的问题就是求送回多少量,送回辆数 = -sent-(-collect)=collect-sent=-5-(-8)=3, 送回3辆,其实就是collect代表如果能拿后面的自行车来补前面的还需多少辆,而sent代表从前往后送至少送多少辆就足以。所以两者相减代表送回的车数。还有一种简单的情况如下:

5 6 5 7 8 9
0 1 0 3 6 11

  这种情况就是collect不会出现负值,就是代表不需要从原点取车,这种情况比较简单,而送回的车数就等于collect最后的值。

  主要思想如上,然后就是当找到一点较短路径时,将节点信息复制(i = kk),并做相应的collect ,sent值更新,以及将前驱结点加入vector<int>中, 若找到相同距离的路径,将此结点信息加入到目标节点中(kk的信息加入到i的信息中),再做类似更新。 

  最后直接找到S结点的信息,对所有最短路径排序选出最优,输出即可。

 

  1 #include<iostream>
  2 #include<map>
  3 #include<utility>
  4 #include<vector>
  5 #include<algorithm>
  6 using namespace std;
  7 
  8 #define INF 9999999
  9 
 10 struct Node
 11 {
 12     int sent;
 13     int collect;
 14 };
 15 
 16 /*排序谓词函数,用于选出最优路径,即是送出自行车最少,送回自行车最少*/
 17 bool comp(pair<Node, vector<int>> p1, pair<Node, vector<int>> p2)
 18 {
 19     if(p1.first.sent > p2.first.sent)
 20         return true;
 21     else if(p1.first.sent == p2.first.sent && p1.first.collect < p2.first.collect)
 22         return true;
 23     else
 24         return false;
 25 }
 26 
 27 void Dijkstra_version(vector<vector<int>> &gra, vector<int> &bike, int C, int S)
 28 {
 29     int start = 0;
 30     vector<int> used(gra.size(), 0);
 31     map<int, vector<pair<Node, vector<int>>>> info;
 32     /*保存每个结点的信息,信息表明到此结点有几条最短路径,
 33     分别是什么,以及需要从原点取及其放回多少量自行车*/
 34     vector<int> ri;
 35     Node n={INF, 0};
 36     pair<Node, vector<int>> zero(n,ri);
 37     info[0].push_back(zero);
 38     /*更新原点信息*/
 39     vector<int> dist(gra.size(), INF);
 40     dist[0] = 0;
 41     
 42     while(start != S)
 43     {
 44         int min = INF; int kk = -1;
 45         for(int i=0; i<dist.size(); ++i)
 46             if(used[i] == 0 && dist[i] < min)
 47             {
 48                 min = dist[i];
 49                 kk = i;
 50             }
 51         used[kk] = 1;
 52         for(int i=0; i<dist.size(); ++i)
 53             if(used[i] == 0)
 54                 if(gra[kk][i] + dist[kk] < dist[i])
 55                 {
 56                     dist[i] = gra[kk][i] + dist[kk];
 57                     /*当有较短路径出现时,替换原来结点的信息*/
 58                     info[i] = info[kk];
 59                     for(int j=0; j < info[i].size(); ++j)
 60                     {
 61                         /*替换后,对结点的信息更新,collect记录信息,此信息现在虽无具体意义,
 62                         但是后面要用它计算送回多少量自行车,sent用来记录从原来送出多少自行车*/
 63                         info[i][j].first.collect += (bike[i] - C/2);
 64                         if(info[i][j].first.collect < info[i][j].first.sent)
 65                             info[i][j].first.sent = info[i][j].first.collect;
 66                         info[i][j].second.push_back(kk);
 67                     }
 68                 }
 69                 else if(gra[kk][i] + dist[kk] == dist[i] && dist[i] != INF)
 70                 {
 71                     /*要把KK结点的信息更新并加入i节点中*/
 72                     for(int j=0; j < info[kk].size(); ++j)
 73                     {
 74                         info[i].push_back(info[kk][j]);
 75                         info[i][info[i].size()-1].first.collect += (bike[i] - C/2);
 76                         if(info[i][info[i].size()-1].first.collect < info[i][info[i].size()-1].first.sent)
 77                             info[i][info[i].size()-1].first.sent = info[i][info[i].size()-1].first.collect;
 78                         info[i][info[i].size()-1].second.push_back(kk);
 79                     }
 80                 }
 81         start = kk;
 82     }
 83     for(int i=0; i<info[S].size(); ++i)
 84     {
 85         /*若sent>=0,则代表不需要送出自行车,负数代表要送出自行车*/
 86         if(info[S][i].first.sent >= 0)
 87             info[S][i].first.sent = 0;
 88         else
 89         {
 90             /*更新collect,使collect最终表示有多少辆车要送回去*/
 91             info[S][i].first.collect -= info[S][i].first.sent;
 92         }
 93     }
 94     sort(info[S].begin(), info[S].end(), comp);
 95     /*排序得最优*/
 96     pair<Node, vector<int>> v=*(info[S].begin());
 97     cout<<0-v.first.sent<<" ";
 98     for(int i=0; i<v.second.size(); ++i)
 99         cout<<v.second[i]<<"->";
100     cout<<S<<" "<<v.first.collect<<endl;
101 }
102 
103 int main()
104 {
105     int C, N, S, M;
106     while(cin>>C>>N>>S>>M)
107     {
108         vector<int> colum(N+1, INF);
109         vector<vector<int>> gra(N+1, colum);
110         vector<int> bikes(N+1,-1);
111         for(int i=1; i<=N; ++i)
112             cin>>bikes[i];
113         for(int i=0; i<M; ++i)
114         {
115             int a,b,c; cin>>a>>b>>c;
116             gra[a][b]=gra[b][a]=c;
117         }
118         Dijkstra_version(gra, bikes, C, S);
119     }
120     return 0;
121 }

 

 

 

posted @ 2013-10-07 19:15  coding_monkey  阅读(344)  评论(0编辑  收藏  举报