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

这样就建好图了。

然后再跑最小流就好了。

 

代码:

#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;
}
View Code

 

posted @ 2019-07-01 14:10  Schenker  阅读(444)  评论(0编辑  收藏  举报