zoukankan      html  css  js  c++  java
  • 「网络流24题」「LuoguP4014」 分配问题

    Description


    有 n 件工作要分配给 n 个人做。第 i 个人做第 j 件工作产生的效益为 cij。试设计一个将 n 件工作分配给 n 个人做的分配方案,使产生的总效益最大。

    Input


    文件的第 1 行有 1 个正整数 n ,表示有 n 件工作要分配给 n 个人做。

    接下来的 n 行中,每行有 n 个整数 cij​​,表示第 i 个人做第 j 件工作产生的效益为 cij​ 。

    Output


    两行分别输出最小总效益和最大总效益。

    Sample Input


    5
    2 2 2 1 2
    2 3 1 2 4
    2 0 1 1 1
    2 3 4 3 3
    3 2 1 2 1

    Sample Output


    5
    14

    Hint


    1≤n≤100

    一个人只能修一个工件

    题解


    还挺裸的感觉。

    s连每个人,流量1,费用0

    每个人连每个任务,流量1,费用cij

    每个任务连t,流量1,费用0

    跑一遍最小费用最大流输出答案

    然后把每条边流量复原,费用取反跑最小费用,

    这样跑出来的结果再取个反就是最大费用了。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    using namespace std;
    const int INF=999999999;
    struct emm{
        int e,f,v,c;
    }a[100007];
    int h[207];
    int tot=1;
    void con(int u,int v,int w,int c)
    {
        a[++tot].f=h[u];
        h[u]=tot;
        a[tot].e=v;
        a[tot].v=w;
        a[tot].c=c;
        a[++tot].f=h[v];
        h[v]=tot;
        a[tot].e=u;
        a[tot].c=-c;
        return;
    }
    bool sf[207];
    int d[207];
    int s,t;
    queue<int>q;
    bool spfa()
    {
        memset(sf,0,sizeof(sf));
        memset(d,127,sizeof(d));
        d[s]=0;sf[s]=1;q.push(s);
        while(!q.empty())
        {
            int x=q.front();q.pop();
            for(int i=h[x];i;i=a[i].f)
            if(d[a[i].e]>d[x]+a[i].c&&a[i].v)
            {
                d[a[i].e]=d[x]+a[i].c;
                if(!sf[a[i].e])
                {
                    sf[a[i].e]=1;
                    q.push(a[i].e);
                }
            }
            sf[x]=0;
        }
        return d[t]<INF;
    }
    int ans=0;
        int tim=0;
    int dfs(int x,int al)
    {
        if(x==t||!al)return al;
        int fl=0;
        for(int i=h[x];i;i=a[i].f)
        if(d[a[i].e]==d[x]+a[i].c&&a[i].v&&!sf[a[i].e])
        {
            sf[a[i].e]=1;
            int f=dfs(a[i].e,min(al,a[i].v));
            if(f)
            {
                fl+=f;
                al-=f;
                ans+=f*a[i].c;
                a[i].v-=f;
                a[i^1].v+=f;
                if(!al)break;
            }
        }
        if(!fl)d[x]=INF;
        return fl;
    }
    int main()
    {
        //freopen("a.in","r",stdin);
        int n;
        scanf("%d",&n);
        s=0,t=2*n+1;
        for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
        {
            int x;
            scanf("%d",&x);
            con(i,j+n,1,x);
        }
        for(int i=1;i<=n;++i)
        {
            con(s,i,1,0);
            con(i+n,t,1,0);
        }
        while(spfa())
        {
            sf[t]=1;
            while(sf[t])
            {
                memset(sf,0,sizeof(sf));
                dfs(s,INF);
            }
        }
        cout<<ans<<endl;
        for(int i=2;i<=tot;i+=2)
        {
            a[i].v+=a[i^1].v;
            a[i^1].v=0;
            swap(a[i].c,a[i^1].c);
        }
        ans=0;
        while(spfa())
        {
            sf[t]=1;
            while(sf[t])
            {
                memset(sf,0,sizeof(sf));
                dfs(s,INF);
            }
        }
        cout<<-ans<<endl;
        return 0;
    }
    
    
  • 相关阅读:
    洛谷 P5564: [Celeste-B]Say Goodbye
    LOJ 3185: 「CEOI2018」斐波那契表示法
    Codeforces 749E: Inversions After Shuffle
    C#之在treeview中鼠标点击的所选的节点触发事件
    C#中选中指定文件并读取类似ini文件的内容
    免费的EmBitz可替代Keil MDK开发STM32、NXP项目
    C#创建子线程,子线程使用委托更新控件
    C#调用C++生成的动态链接库DLL
    C#之菜单控件、主窗体打开子窗体、GroupBox控件使用
    在Linux下用CANopenSocket协议模拟CAN总线通讯
  • 原文地址:https://www.cnblogs.com/qwerta/p/9379733.html
Copyright © 2011-2022 走看看