洛谷 P4014:「分配问题」
热度: loading...
题目描述
有n件工作要分配给n个人做.第i个人做第j件工作产生的效益为.试设计一个将n件工作分配给n个人做的分配方案,使产生的总效益最大.
输入格式
文件的第1行有1个正整数n,表示有n件工作要分配给n个人做.
接下来的n行中,每行有n个整数 ,表示第i个人做第j件工作产生的效益为.
输出格式
两行分别输出最小总效益和最大总效益。
输入输出样例
样例输入
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
说明/提示
1n
一个人只能修一个工件
这是一道费用流经典题目
建图
- 1.设0为超级源点,2n+1为超级汇点,第i个人的节点为i,第j件工作节点为j+n
- 2.从超级源点 向i[1,n]连接一条容量为1,费用为0的边
- 3.从j[n+1,2n]向超级汇点连接一条容量为1,费用为的边
- 4.从i [1, n]向j [n+1,n 2],连接一条容量为1,费用为的边
做法
跑一遍最小费用最大流&最大费用最小流,然后再分别输出最小值与最大值
(温馨提醒:一定要输出,不然会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:月雩·薇嫭
洛谷 P2713:「罗马游戏」
上一篇 洛谷 P2713:「罗马游戏」