Sample Input:
10 3 3 5
6 7 0
0 1 1
0 2 1
0 3 3
1 3 1
2 3 1
Sample Output:
3 0->2->3 0
题目大意
杭州市的自行车站管理系统,每个站点都有一定数量的自行车,数量处于最大值一半的状态是“perfect condition”(有车可借,有空位可还车),如果数量是0,称之为“problem condition”,需要从调度中心去运送车辆。运送路程中,如果经过自行车站点,会顺带调整该站点的状态,多的车子带走,少的顺带补齐。已知各个自行车站点的通车时间,求问最短的行车路线,如果存在多个最短路线,那么需要补送自行车最少的一个是多少。
- 找最短路径;
- 若不唯一,找其中需要送出自行车最少的路径;
- 若还不唯一,找其中需要回收自行车最少的路径;
解题思路
题目的本质实质上是求带权单源最短路径,可以使用Dijkstra算法,但可能存在多个最短路径,所以还要在最后的结果中使用深度优先搜索判断哪个是最符合条件的。
坑
只能沿着最短路径的方向收集多余自行车,分给后面的节点;后面节点多出来的不能填到前面去,只能计入回收总量。
例如路径上自行车数为5->0->10,并不能把最后一个节点上挪5个给中间的,需要送出5个,并回收5个。
测试点5和7。
1 #include <iostream>
2 #include <cstdio>
3 #include <vector>
4
5 #define INF 1000000000
6
7 using namespace std;
8
9 int dist[510];
10 vector<int> pre[510];
11 vector<int> path, tmp;
12 int g[510][510];
13 int s[510];
14 int vis[510];
15 int C, N, Sp, M;
16 int minNeed = INF; //需要额外带的自行车
17 int back = INF; //需要带回去的自行车
18
19 /*
20 10 3 3 3
21 5 0 10
22 0 1 1
23 1 2 1
24 2 3 1
25 */
26
27 //先假设最短路唯一,看看能得多少分
28 void dijkstra (int start)
29 {
30 for(int i = 0; i <= N; ++i)
31 {
32 dist[i] = INF;
33 vis[i] = 0;
34 }
35 dist[start] = 0;
36
37 while(1)
38 {
39 int mark = -1, minDist = INF;
40 for(int i = 0; i <= N; ++i)
41 {
42 if(!vis[i] && dist[i] < minDist)
43 {
44 minDist = dist[i];
45 mark = i;
46 }
47 }
48
49 if(mark == -1)
50 break;
51
52 vis[mark] = 1;
53
54 for(int i = 0; i <= N; ++i)
55 {
56 if(!vis[i])
57 {
58 if(dist[mark] + g[mark][i] < dist[i])
59 {
60 dist[i] = dist[mark] + g[mark][i];
61 pre[i].clear();
62 pre[i].push_back(mark); // 记录路径
63 }
64 else if(dist[mark] + g[mark][i] == dist[i])
65 {
66 pre[i].push_back(mark); // 记录路径
67 }
68 }
69 }
70 }
71
72 }
73
74 void dfs(int v)
75 {
76 // 深度优先路过的顶点,存入tmp
77 tmp.push_back(v);
78 // 当到达顶点0的时候,开始计算
79 if(v == 0)
80 {
81 int perfectnum = C/2;
82 int difference;
83 int need = 0; //需要带的自行车
84 int available = 0; //可用的(多余的)自行车
85 for(int i = tmp.size()-2; i >= 0; --i)
86 {
87 if(s[tmp[i]] > perfectnum)
88 {
89 // 有单车多余
90 difference = s[tmp[i]] - perfectnum;
91 available += difference;
92 }
93 else if(s[tmp[i]] < perfectnum)
94 {
95 // 单车不够
96 difference = perfectnum - s[tmp[i]];
97 if(available >= 0)
98 {
99 if(available > difference)
100 {
101 // 此时need数量不变
102 available -= difference;
103 }
104 else
105 {
106 need += difference - available;
107 available = 0;
108 }
109
110 }
111 }
112 }
113
114 if(need < minNeed)
115 {
116 minNeed = need;
117 back = available;
118 path = tmp;
119 } else if(need == minNeed && available < back)
120 {
121 back = available;
122 path = tmp;
123 }
124
125 // 顶点在dfs访问结束后弹出
126 tmp.pop_back();
127 return;
128 }
129
130 for(int i = 0; i < pre[v].size(); ++i)
131 dfs(pre[v][i]);
132
133 tmp.pop_back(); // 该顶点在dfs访问结束后弹出
134 }
135
136 int main()
137 {
138 scanf("%d%d%d%d", &C, &N, &Sp, &M);
139 for(int i = 1; i <= N; ++i)
140 scanf("%d", &s[i]);
141
142 for(int i = 0; i <= N; ++i)
143 {
144 for(int j = 0; j <= N; ++j)
145 {
146 if(i == j)
147 g[i][j] = 0;
148 else
149 g[i][j] = INF;
150 }
151 }
152
153 int a, b, cost;
154 for(int i = 0; i < M; ++i)
155 {
156 scanf("%d%d%d", &a, &b, &cost);
157 g[a][b] = g[b][a] = cost;
158 }
159
160 dijkstra(0);
161 dfs(Sp);
162
163 printf("%d 0", minNeed);
164
165 int psize = path.size();
166 for(int i = psize-2; i >= 0; --i)
167 {
168 printf("->%d", path[i]);
169 }
170
171 printf(" %d", back);
172
173 return 0;
174 }