zoukankan      html  css  js  c++  java
  • 【洛谷P4014】【网络流24题】分配问题【费用流】

    题目大意:

    题目大意:https://www.luogu.org/problemnew/show/P4014
    nn件工作要分配给nn个人做。第ii个人做第jj件工作产生的效益为cijc_{ij}。试设计一个将nn件工作分配给nn个人做的分配方案,求最大效益和最小效益。


    思路:

    超级裸的一道费用流。
    源点连向所有的人,所有的工作连向汇点。流量为11,费用为00
    中间所有的人连向工作,流量为11,费用为cijc_{ij}
    跑一遍最小费用最大流就求出了第一问的答案。
    然后将所有边的费用取反,跑一遍就是最大费用最大流。
    在这里插入图片描述
    注意要用spfaspfadijdij不支持跑负环。


    代码:

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #define mp make_pair
    using namespace std;
    
    const int N=110;
    int n,x,tot=1,S,T,cost,head[N*2],dis[N*2],per[N*2],c[N][N];
    bool vis[N*2];
    
    struct edge
    {
    	int from,to,flow,cost,next;
    }e[2*(N*N+N+N)];
    
    void add(int from,int to,int flow,int cost)
    {
    	e[++tot].to=to;
    	e[tot].from=from;
    	e[tot].flow=flow;
    	e[tot].cost=cost;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    bool spfa()
    {
    	memset(dis,0x3f3f3f3f,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	memset(per,0,sizeof(per));
    	queue<int> q;
    	q.push(S);
    	vis[S]=1;
    	dis[S]=0;
    	while (q.size())
    	{
    		int u=q.front();
    		q.pop();
    		vis[u]=0;
    		for (int i=head[u];~i;i=e[i].next)
    		{
    			if (!e[i].flow) continue;
    			int v=e[i].to;
    			if (dis[v]>dis[u]+e[i].cost)
    			{
    				dis[v]=dis[u]+e[i].cost;
    				per[v]=i;
    				if (!vis[v])
    				{
    					vis[v]=1;
    					q.push(v);
    				}
    			}
    		}
    	}
    	return dis[T]<1e9;
    }
    
    void addflow()
    {
    	int minflow=2147483647;
    	for (int i=T;i!=S;i=e[per[i]].from)
    		minflow=min(minflow,e[per[i]].flow);
    	for (int i=T;i!=S;i=e[per[i]].from)
    	{
    		e[per[i]].flow-=minflow;
    		e[per[i]^1].flow+=minflow;
    	}
    	cost+=minflow*dis[T];
    }
    
    void mcmf()
    {
    	while (spfa())
    		addflow();
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=n;j++)
    		{
    			scanf("%d",&c[i][j]);
    			add(i,j+n,1,c[i][j]);
    			add(j+n,i,0,-c[i][j]);
    		}
    	S=n+n+1;
    	T=n+n+2;
    	for (int i=1;i<=n;i++)
    	{
    		add(S,i,1,0);
    		add(i,S,0,0);
    		add(i+n,T,1,0);
    		add(T,i+n,0,0);
    	}
    	mcmf();
    	printf("%d
    ",cost);
    	
    	//////////////////////////////////////////////////////////////
    	
    	memset(head,-1,sizeof(head));
    	memset(e,0,sizeof(e));
    	tot=1; 
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=n;j++)
    		{
    			add(i,j+n,1,-c[i][j]);
    			add(j+n,i,0,c[i][j]);
    		}
    	S=n+n+1;
    	T=n+n+2;
    	for (int i=1;i<=n;i++)
    	{
    		add(S,i,1,0);
    		add(i,S,0,0);
    		add(i+n,T,1,0);
    		add(T,i+n,0,0);
    	}
    	cost=0;
    	mcmf();
    	printf("%d
    ",-cost);
    	return 0;
    }
    
  • 相关阅读:
    多线程编程(2):线程的同步
    C#中listview实现排序
    [PLC]S7-300的数据类型
    C# 多线程编程(4):多线程与UI操作
    Thunderbird 80 column FIX 发出的邮件也需要在80列处line break
    vsftp 500 OOPS: vsftpd: refusing to run with writable anonymous root
    科普 What is YUV
    转载:网站真的可以无密码登录么?
    Ubuntu 12.04安装Microsoft lifecam studio摄像头
    Thunderbird on Ubuntu 12.04 调整邮件列表行间距
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998361.html
Copyright © 2011-2022 走看看