[SCOI2007]修车 题解

上古网络流题

为了便于考虑每个决策的贡献,把每个工人的决策拆成N个彼此独立的决策:即其修的倒数第i个车是什么。因为此车后(含此车)有i人要多等T,故贡献为T*n

以此拆点建图,以贡献为费用跑(二分图)费用流即可,由费用流性质可知每人修车顺序必合法

注意本题N,M顺序有点反常

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;

const int maxn=400005;
const int inf = 0x3f3f3f3f;
int n, m, maxflow, mincost;

struct gra {
    int tm, st[maxn], to[maxn], nx[maxn], c[maxn], d[maxn];
    int dis[maxn], inq[maxn], flow[maxn];
    int pre[maxn], last[maxn];
    queue <int> q;
    void cle() {
        tm=-1;
        memset(st, -1, sizeof(st));
    }
    void adde(int a, int b, int cc, int dd) {
        //cout<<a<<' '<<' '<<b<<' '<<cc<<' '<<dd<<endl;;
        tm++;
        nx[tm]=st[a];
        st[a]=tm;
        to[tm]=b;
        c[tm]=cc;
        d[tm]=dd;
        
        tm++;
        nx[tm]=st[b];
        st[b]=tm;
        to[tm]=a;
        c[tm]=0;
        d[tm]=-dd;
    }
    bool spfa(int s, int t) {
        memset(dis, 0x3f, sizeof(dis));
        memset(inq, 0, sizeof(inq));
        memset(flow, 0, sizeof(flow));
        memset(pre, 0, sizeof(pre));
        memset(last, 0, sizeof(last));
        flow[s]=inf;
        int x, y, i;
        q.push(s); inq[s]=1;
        dis[s]=0; pre[t]=-1;
        while(!q.empty()) {
            x=q.front();
            q.pop();
            inq[x]=0;
            for(i=st[x]; i != -1; i=nx[i]) {
                y=to[i];
                if(c[i] > 0 && dis[y] > dis[x]+d[i]) {
                    dis[y] = dis[x]+d[i];
                    pre[y]=x;
                    last[y]=i;
                    flow[y]=min(flow[x], c[i]);
                    if(!inq[y]) {
                        inq[y]=1; q.push(y);
                    }
                }
            }
        }
        return (pre[t] != -1);
    }
    void count(int s, int t) {
        int x;
        while(spfa(s, t)) {
            int x=t;
            maxflow+=flow[t];
            mincost+=flow[t]*dis[t];
            while(x != s) {
                c[last[x]]-=flow[t];
                c[(last[x]^1)]+=flow[t];
                x=pre[x];
            }
        }
        return;
    }
} G;

int main() {
    ios::sync_with_stdio(false);
    G.cle();
    double ans;
    int i, j, ta, tb, tc, td, S, T, k;
    cin>>n>>m;
    S=n*m+m+1; T=n*m+m+2;
    for(i=1; i <= n*m; i++) G.adde(S, i, 1, 0);
    for(i=1; i <= m; i++) G.adde(i+n*m, T, 1, 0);
    for(i=1; i <= m; i++) {
        for(j=1; j <= n; j++) {
            cin>>ta;
            for(k=1; k <= m; k++) 
                G.adde(m*(j-1)+k, i+n*m, 1, ta*k);
        }
    }
    G.count(S, T);
    ans=(mincost*1.0)/m;
    printf("%.2lf\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/crraphael/p/11346226.html
今日推荐