月雩の小窝(损坏)
 
Made by 月雩 禁止转载(作者允许除外) | Theme: Fog
载入天数...
载入时分秒...
总访问量:  |   访问人数:
Copyright © 2020 pray-yueyu.github.io

洛谷 P4014:「分配问题」

  热度: loading...

题目链接

题目描述

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

输入格式

文件的第1行有1个正整数n,表示有n件工作要分配给n个人做.
接下来的n行中,每行有n个整数 CijC_{ij},表示第i个人做第j件工作产生的效益为CijC_{ij}.

输出格式

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

输入输出样例

样例输入

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

样例输出

5
14

说明/提示

1\len100\le100
一个人只能修一个工件

这是一道费用流经典题目

建图

  • 1.0超级源点2×\timesn+1超级汇点,第i个人的节点为i,第j件工作节点为j+n
  • 2.超级源点\foralli\in[1,n]连接一条容量为1,费用为0的边
  • 3.\forallj\in[n+1,2×\timesn]向超级汇点连接一条容量为1,费用为00的边
  • 4.从\foralli\in [1, n]向\forallj\in [n+1,n×\times 2],连接一条容量为1,费用为Ci,jC_{i, j}的边

做法

跑一遍最小费用最大流&最大费用最小流,然后再分别输出最值与最
(温馨提醒:一定要输出,不然会WA!)

为各位大佬献上我丑陋的代码~

#include<bits/stdc++.h>
#define FQ(i,a,b) for(register int i=a;i<=b;i++)
#define prf printf
#define scf scanf
#define ll long long
using namespace std;
const int N=5e4+10;
int INF,n,num=1,ne[N],fi[N],to[N],w[N],pl[N],S,T;
int dst[N],incf[N],P[N],vis[N],ans;
queue<int> q;
void FindMaxN()
{
	int fINDmAXn[1];
	memset(fINDmAXn,128/2,sizeof(fINDmAXn));	
	INF=fINDmAXn[0];
}
ll read()
{
	ll x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;	
}
void add(int x,int y,int z,int kl)
{
    ne[++num]=fi[x];    
    fi[x]=num;    
    to[num]=y;   
    w[num]=z;
    pl[num]=kl; 
}
bool spfa()
{ 
    for(int i=S;i<=T;i++)dst[i]=INF; 
    memset(vis,0,sizeof(vis));  
    q.push(S),dst[S]=0;	
	incf[S]=1<<30,vis[S]=true;   
    while(!q.empty())
    {      
        int x=q.front();      
        vis[x]=false;q.pop();        
        for(int i=fi[x];i;i=ne[i])
        {            
            int ver=to[i];             
            if(dst[ver]>dst[x]+pl[i]&&w[i])
            {                
                dst[ver]=dst[x]+pl[i];                
                incf[ver]=min(incf[x],w[i]);                
                P[ver]=i;                
                if(!vis[ver])vis[ver]=true,q.push(ver);                 
            }             
        }    
    }
    return dst[T]!=INF;  
}
void update()
{	
	int x=T;     
    while(x!=S)
    {         
        int i=P[x];         
        w[i]-=incf[T];       
        w[i^1]+=incf[T];
   
        x=to[i^1];
    }
    ans+=dst[T]*incf[T];
}
bool spfa_d()
{
    for(int i=S;i<=T;i++)dst[i]=-INF;
    q.push(S),dst[S]=0;incf[S]=1<<30;
    while(!q.empty())
    {
        int x=q.front();
        vis[x]=false;q.pop();
        for(int i=fi[x];i;i=ne[i])
        {
            int ver=to[i];
            if(dst[ver]<dst[x]+pl[i]&&w[i])
            {
                dst[ver]=dst[x]+pl[i];
                incf[ver]=min(incf[x],w[i]);
                P[ver]=i;
                if(!vis[ver])vis[ver]=true,q.push(ver);
            }
        }
    }
    return dst[T]!=-INF;
}
void update_d()
{
	int x=T;
    while(x!=S)
    {
        int i=P[x];
        w[i]-=incf[T];
        w[i^1]+=incf[T];
        x=to[i^1];
    }
    ans+=dst[T]*incf[T];
}
void add_x(int x,int y,int z,int kl)
{
	add(x,y,z,kl);
	add(y,x,0,-kl);
}
int main()
{
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	FindMaxN();
	n=read();S=0,T=n*2+1;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			int x=read();
			add_x(i,j+n,1,x);
		}
	}
	for(int i=1;i<=n;i++)add_x(S,i,1,0),add_x(i+n,T,1,0);
	while(spfa())update();
	printf("%d\n",ans);
	ans=0;
	for(int i=2;i<=num;i+=2)w[i]+=w[i^1],w[i^1]=0;
	while(spfa_d())update_d();
	printf("%d\n",ans);
	return 0;		
}
//**月雩·薇嫭**

by:月雩·薇嫭