SDOI 2010 星际竞速

题目描述 Description

10 年一度的银河系赛车大赛又要开始了。作为全银河最盛大的活动之一,夺得这个项目的冠军无疑是很多人的梦想,来自杰森座 α星的悠悠也是其中之一。

赛车大赛的赛场由 N 颗行星和M条双向星际航路构成,其中每颗行星都有一个不同的引力值。大赛要求车手们从一颗与这 N 颗行星之间没有任何航路的天体出发,访问这 N 颗行星每颗恰好一次,首先完成这一目标的人获得胜利。 
由于赛制非常开放,很多人驾驶着千奇百怪的自制赛车来参赛。这次悠悠驾驶的赛车名为超能电驴,这是一部凝聚了全银河最尖端科技结晶的梦幻赛车。作为最高科技的产物,超能电驴有两种移动模式:高速航行模式和能力爆发模式。在高速航行模式下,超能电驴会展开反物质引擎,以数倍于光速的速度沿星际航路高速航行。在能力爆发模式下,超能电驴脱离时空的束缚,使用超能力进行空间跳跃——在经过一段时间的定位之后,它能瞬间移动到任意一个行星。 
天不遂人愿,在比赛的前一天,超能电驴在一场离子风暴中不幸受损,机能出现了一些障碍:在使用高速航行模式的时候,只能由每个星球飞往引力比它大的星球,否则赛车就会发生爆炸。 
尽管心爱的赛车出了问题,但是悠悠仍然坚信自己可以取得胜利。他找到了全银河最聪明的贤者——你,请你为他安排一条比赛的方案,使得他能够用最少的时间完成比赛。

输入描述 Input Description

第一行是两个正整数 N, M。 
第二行 N 个数 A1~AN, 其中Ai表示使用能力爆发模式到达行星 i 所需的定位
时间。 
接下来 M行,每行 3个正整数ui, vi, wi,表示在编号为 ui和vi的行星之间存在一条需要航行wi时间的星际航路。 
输入数据已经按引力值排序,也就是编号小的行星引力值一定小,且不会有两颗行星引力值相同。

输出描述 Output Description

仅包含一个正整数,表示完成比赛所需的最少时间。

样例输入 Sample Input

3 3 
1 100 100 
2 1 10 
1 3 1 
2 3 1

样例输出 Sample Output

12 

数据范围及提示 Data Size & Hint

对于 30%的数据 N≤20,M≤50; 
对于 70%的数据 N≤200,M≤4000; 
对于100%的数据N≤800, M≤15000。输入数据中的任何数都不会超过106
。 
输入数据保证任意两颗行星之间至多存在一条航道,且不会存在某颗行星到
自己的航道。

 
首先,这是一道裸眼网络流问题,最小费用最大流,流表示流经的点的数目,费用表示路程。
我们可以将每个点拆成两个点,入点和出点。如果有一条边(U,V),那么我们就从U的出点连一条权值为这条路的路程的边到V的入点,容量为1。然后我们在每个入点里连一条容量为1,花销为0的边到汇点,表示该点是否被访问。再将起点向每个入点连一条容量1,花销为固定费用的边,表示瞬移道路。因为,每当我们经过一个入点后,流入的一点流都会注入汇点,所以,我们无法继续从这个入点开始引流。为了解决这个问题,我们从起点向每个出点连一条容量1,花销0的边,这样,当我们每走完一个节点后,为了继续流动都会返回起点,然后从起点流向一个出点。因为从起点走出的流量只有1,所以从这个出点也只能到达一个入点,也就保证了行走路径必然是一条线,而不会出现分叉。
 
不需要担心会不会出现环,因为每个点都是从比编号比他小的点或者起点过来的,所以,他的流一定不会回到之前的点中。同时,因为每个点不会从比他大的点过来,所以一定有至少一个点(第一个点)是从起点瞬移过来的,也就保证了答案的合理性。
 
代码(如果需要注释,可以参考http://www.cnblogs.com/xstsow/p/4346489.html中的代码注释)
 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 << "
";
90     return 0;
91 }
原文地址:https://www.cnblogs.com/xstsow/p/4386470.html