zoukankan      html  css  js  c++  java
  • [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
    ", ans);
        return 0;
    }
  • 相关阅读:
    Python初学者第十天 集合、十六进制
    Python初学者第九天 字符串、列表、字典练习
    Python初学者第八天 元组和字典
    Python初学者第七天 字符串及简单操作
    Python初学者第六天 列表操作练习
    Python初学者第五天 列表及简单操作
    Python初学者第四天 二进制运转换
    Python初学者第三天 运算符、while循环
    Python初学者第二天 用户输入和注释
    Python初学者第一天 Python安装及第一个Python程序
  • 原文地址:https://www.cnblogs.com/crraphael/p/11346226.html
Copyright © 2011-2022 走看看