题意:给定一个图,还有一些有向边,每条边有一个权值w。对于每一个点,可以从其他任意一个点转移到这个点,时间为t。求从图外的一个点(即第一次一定是通过转移方式),遍历图中每个点一次最少需要的时间。。
思路:
对于图中的每个点,需要满足的要求是进入一次,出去一次(即遍历一边)
所以我们很容易想到拆点,把每个点拆成两个点。建图如下:
<S, i, 1, 0>对应每个点进入一次
<i+n, T, 1, 0>对应每个点出去一次
<i, j + n, 1, wij>,如果ij有边对应i走到j
<S, i, 1, t[i]>对应可以从其他点转移到这个点
这样跑一遍最小费用流就是答案。
code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define M0(a) memset(a, 0, sizeof(a)) 4 #define Inf 0x3fffffff 5 const int maxn = 2010; 6 const int maxm = 200010; 7 struct edge{ 8 int v, f, c, next; 9 edge(){} 10 edge(int _v, int _f, int _c, int _next):v(_v), f(_f), c(_c), next(_next){} 11 }; 12 struct Costflow{ 13 int last[maxn], pre[maxn], dis[maxn], vis[maxn]; 14 int tot, S, T; 15 edge e[maxm]; 16 void add(int u, int v, int f, int c){ 17 e[tot] = edge(v, f, c, last[u]); last[u] = tot++; 18 e[tot] = edge(u, 0, -c, last[v]); last[v] = tot++; 19 } 20 void init(int S, int T){ 21 this->S = S, this->T = T; 22 M0(e); 23 memset(last, -1, sizeof(last)); 24 tot = 0; 25 } 26 int spfa(){ 27 for (int i = 0; i <= T; ++i) 28 dis[i] = Inf; 29 memset(vis, 0, sizeof(vis)); 30 memset(pre, -1, sizeof(pre)); 31 dis[S] = 0; 32 queue<int> q; 33 q.push(S) , vis[S] = 1; 34 int p, u, v; 35 while (!q.empty()){ 36 p = last[u = q.front()]; 37 for ( ; p > -1; p = e[p].next){ 38 v = e[p].v; 39 if (dis[u] + e[p].c < dis[v] && e[p].f > 0){ 40 dis[v] = dis[u] + e[p].c; 41 pre[v] = p; 42 if (!vis[v]) vis[v] = 1, q.push(v); 43 } 44 } 45 vis[u] = 0; 46 q.pop(); 47 } 48 return dis[T] < Inf; 49 } 50 int costflow(){ 51 int cost = 0, flow = 0; 52 while (spfa()){ 53 int f = Inf; 54 for (int p = pre[T]; p != -1; p = pre[e[p^1].v]) 55 f = min(f, e[p].f); 56 flow += f; 57 cost += f * dis[T]; 58 for (int p = pre[T]; p != -1; p = pre[e[p^1].v]) 59 e[p].f -= f, e[p^1].f += f; 60 } 61 return cost; 62 } 63 /***********/ 64 } F; 65 int n, m; 66 int t[maxn]; 67 68 void solve(){ 69 // printf("%d %d\n", n, m); 70 for (int i = 1; i <= n; ++i) 71 scanf("%d", t+i); 72 int S = 0, T = 2 * n + 1; 73 F.init(S, T); 74 for (int i = 1; i <= n; ++i) 75 F.add(S, i + n, 1, t[i]), F.add(i+n, T, 1, 0), F.add(S, i, 1, 0); 76 int u, v, w; 77 for (int i = 1; i <= m; ++i){ 78 scanf("%d%d%d", &u, &v, &w); 79 if (u > v) swap(u, v); 80 F.add(u, v+n, 1, w); 81 } 82 int ans = F.costflow(); 83 cout << ans << endl; 84 } 85 86 int main(){ 87 while (scanf("%d%d", &n, &m) != EOF){ 88 solve(); 89 } 90 }
时间: 2024-10-09 12:24:11