CodeForces 1187G Gang Up 费用流
题解:
先按时间轴将一个点拆成100个点。 第一个点相当于第一秒, 第二个点相当于第二秒。
在这些点之间连边, 每1流量的费用为c。
再将图上的边也拆开。
将 u_i 向 v_i+1 建边。
将 v_i 向 u_i+1 建边。
在上面的建边过程中:
假设最多一条路只会走20个人。
将这个东西拆成20条边。
第i条的流量为1, 费用为 c + ( i*i - (i-1)*(i-1)) * d
这样就建好图了。
然后再跑最小流就好了。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const int _inf = 0xc0c0c0c0; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL _INF = 0xc0c0c0c0c0c0c0c0; const LL mod = (int)1e9+7; const int Z = 100; const int N = Z * Z; const int M = Z * Z * Z; int px[N], py[N]; int head[N], to[M], ct[M], w[M], nt[M]; int d[N], vis[N]; int pre[N], id[N]; int s, t, tot; void add(int u, int v, int flow, int cost){ to[tot] = v; ct[tot] = cost; w[tot] = flow; nt[tot] = head[u]; head[u] = tot++; to[tot] = u; ct[tot] = -cost; w[tot] = 0; nt[tot] = head[v]; head[v] = tot++; } void init(){ memset(head, -1, sizeof(head)); tot = 0; } int spfa(int s, int t){ queue<int> q; memset(d, inf, sizeof(d)); memset(vis, 0, sizeof(vis)); memset(pre, -1, sizeof(pre)); d[s] = 0; q.push(s); while(!q.empty()){ int u = q.front(); q.pop(); vis[u] = 0; for(int i = head[u]; ~i; i = nt[i]){ if(w[i] > 0 && d[to[i]] > d[u] + ct[i]){ d[to[i]] = d[u] + ct[i]; pre[to[i]] = u; id[to[i]] = i; if(!vis[to[i]]){ vis[to[i]] = 1; q.push(to[i]); } } } } return d[t] < inf; } int MinCostFlow(int s, int t){ int Mi = inf; int sum = 0; int tt = 0; while(spfa(s, t)){ Mi = inf; for(int i = t; i != s; i = pre[i]) Mi = min(Mi, w[id[i]]); for(int i = t; i != s; i = pre[i]){ w[id[i]] -= Mi; w[id[i]^1] += Mi; } tt += Mi; sum += d[t] * Mi; } return sum; } int main(){ init(); int n, m, k, c, d; scanf("%d%d%d%d%d", &n, &m, &k, &c, &d); int s = 0, t = n * 100 + 1; for(int i = 1; i <= 100; ++i) add(i, t, 100, 0); for(int i = 1, v; i <= k; ++i){ scanf("%d" , &v); add(s, (v-1)*100+1, 1, 0); } for(int i = 1; i <= n; ++i){ for(int j = 1; j < 100; ++j){ add((i-1)*100 + j, (i-1)*100 + j + 1, 100, c); } } for(int i = 1, u, v; i <= m; ++i){ scanf("%d%d", &u, &v); for(int j = 1; j < 100; ++j){ int idx = (u-1) * 100 + j; int idy = (v-1) * 100 + j + 1; for(int k = 1; k <= 20; ++k){ add(idx, idy, 1, c + (k * k - (k-1) * (k-1))* d) ; } } for(int j = 1; j < 100; ++j){ int idx = (v-1) * 100 + j; int idy = (u-1) * 100 + j + 1; for(int k = 1; k <= 20; ++k){ add(idx, idy, 1, c + (k * k - (k-1) * (k-1))* d) ; } } } printf("%d\n", MinCostFlow(s, t)); return 0; }