SDOI 2010 星际竞速
10 年一度的银河系赛车大赛又要开始了。作为全银河最盛大的活动之一,夺得这个项目的冠军无疑是很多人的梦想,来自杰森座 α星的悠悠也是其中之一。
赛车大赛的赛场由 N 颗行星和M条双向星际航路构成,其中每颗行星都有一个不同的引力值。大赛要求车手们从一颗与这 N 颗行星之间没有任何航路的天体出发,访问这 N 颗行星每颗恰好一次,首先完成这一目标的人获得胜利。
由于赛制非常开放,很多人驾驶着千奇百怪的自制赛车来参赛。这次悠悠驾驶的赛车名为超能电驴,这是一部凝聚了全银河最尖端科技结晶的梦幻赛车。作为最高科技的产物,超能电驴有两种移动模式:高速航行模式和能力爆发模式。在高速航行模式下,超能电驴会展开反物质引擎,以数倍于光速的速度沿星际航路高速航行。在能力爆发模式下,超能电驴脱离时空的束缚,使用超能力进行空间跳跃——在经过一段时间的定位之后,它能瞬间移动到任意一个行星。
天不遂人愿,在比赛的前一天,超能电驴在一场离子风暴中不幸受损,机能出现了一些障碍:在使用高速航行模式的时候,只能由每个星球飞往引力比它大的星球,否则赛车就会发生爆炸。
尽管心爱的赛车出了问题,但是悠悠仍然坚信自己可以取得胜利。他找到了全银河最聪明的贤者——你,请你为他安排一条比赛的方案,使得他能够用最少的时间完成比赛。
第一行是两个正整数 N, M。
第二行 N 个数 A1~AN, 其中Ai表示使用能力爆发模式到达行星 i 所需的定位
时间。
接下来 M行,每行 3个正整数ui, vi, wi,表示在编号为 ui和vi的行星之间存在一条需要航行wi时间的星际航路。
输入数据已经按引力值排序,也就是编号小的行星引力值一定小,且不会有两颗行星引力值相同。
仅包含一个正整数,表示完成比赛所需的最少时间。
3 3
1 100 100
2 1 10
1 3 1
2 3 1
12
对于 30%的数据 N≤20,M≤50;
对于 70%的数据 N≤200,M≤4000;
对于100%的数据N≤800, M≤15000。输入数据中的任何数都不会超过106
。
输入数据保证任意两颗行星之间至多存在一条航道,且不会存在某颗行星到
自己的航道。
1 #include<iostream> 2 #include<cmath> 3 #include<cstdio> 4 #include<queue> 5 #include<vector> 6 #include<cstring> 7 using namespace std; 8 9 const int INF = 0x7fffffff; 10 int n, m, t[801]; 11 long long ans; 12 13 struct Edge{ 14 int from, to, cap, flow, cost; 15 Edge(int r,int o,int c,int f,int s):from(r), to(o), cap(c), flow(f), cost(s){} 16 }; 17 18 struct MCMF{ 19 vector<Edge> edges; 20 vector<int> G[2000]; 21 int p[2000], d[2000], inq[2000], a[2000]; 22 23 void init() { 24 for (int i = 0; i <= 2*n+1; i++) G[i].clear(); 25 edges.clear(); 26 } 27 28 void AddEdge(int from,int to,int cap,int cost) { 29 edges.push_back(Edge(from, to, cap, 0, cost)); 30 edges.push_back(Edge(to, from, 0, 0, -cost)); 31 int m = edges.size(); 32 G[from].push_back(m - 2); 33 G[to].push_back(m - 1); 34 } 35 36 bool BellmanFord(int s, int t, long long& cost) { 37 for (int i = 0; i <= 2*n+1; i++) d[i] = INF; 38 memset(inq, 0, sizeof(inq)); 39 d[s] = 0; inq[s] = 1; p[s] = 0; 40 a[s] = INF; 41 42 queue<int> Q; 43 Q.push(s); 44 while (!Q.empty()) { 45 int u = Q.front(); Q.pop(); 46 inq[u] = 0; 47 for (int i = 0; i < G[u].size(); i++) { 48 Edge& e = edges[G[u][i]]; 49 if (e.cap > e.flow && d[e.to] > d[u] + e.cost) { 50 d[e.to] = d[u] + e.cost; 51 p[e.to] = G[u][i]; 52 a[e.to] = min(a[u], e.cap - e.flow); 53 if (!inq[e.to]) {Q.push(e.to); inq[e.to] = 1;} 54 } 55 } 56 } 57 if (d[t] == INF) return false; 58 cost += (long long) d[t] * (long long) a[t]; 59 for (int u = t; u != s; u = edges[p[u]].from) { 60 edges[p[u]].flow += a[t]; 61 edges[p[u] ^ 1].flow -= a[t]; 62 } 63 return true; 64 } 65 }; 66 67 int main() { 68 scanf("%d%d", &n, &m); 69 MCMF Main; 70 Main.init(); 71 for (int i = 1; i <= n; i++) 72 scanf("%d", &t[i]); 73 for (int i = 1; i <= n; i++) { 74 Main.AddEdge(0, i, 1, 0); 75 Main.AddEdge(n+i+1, n+1, 1, 0); 76 Main.AddEdge(0, n+i+1, 1, t[i]); 77 } 78 for (int i = 0; i < m; i++) { 79 int s, t, cost; 80 scanf("%d%d%d", &s, &t, &cost); 81 if (s > t) { 82 int k = t; 83 t = s; 84 s = k; 85 } 86 Main.AddEdge(s, t+n+1, 1, cost); 87 } 88 while (Main.BellmanFord(0, n+1, ans)) {} 89 cout << ans << "\n"; 90 return 0; 91 }