题目链接:
https://www.luogu.com.cn/problem/P4014
参考博客:https://www.luogu.com.cn/blog/116374/solution-p4014
费用取相反数求最大费用最大流思路来源博客:https://www.luogu.com.cn/blog/luoyuexiu/solution-p4014
思路:
一:建图:
1.设0为超级源点,2 × n+1为超级汇点,第i个人的节点为i,第j件工作节点为j+n
2.从超级源点 向 ∀ i ∈ [1,n]连接一条容量为1,费用为0的边
3.从 ∀ j ∈ [n+1,2 × n]向超级汇点连接一条容量为1,费用为 0 的边
4.从 ∀ i ∈[1, n]向 ∀j ∈ [n+1,n × 2],连接一条容量为1,费用为 Ci,j 的边
二:费用取相反数求最大费用最大流:
只需将原来所有边的费用变为相反数,跑一遍最小费用最大流,就可求出最大值的相反数,输出时再将它取相反数就好啦
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e2+2,maxm=2e4+4e2+1;
int n,s,t,tot=1,head[maxn],dis[maxn],flow[maxn],pre[maxn],last[maxn],maxflow,mincost,m[101][101];
//dis最小花费;pre每个点的前驱;last每个点的所连的前一条边;flow源点到此处的流量
bool vis[maxn];
queue<int>q;
struct edge
{
int to,next,w,dis;//w流量 dis花费
}e[maxm];
void addedge(int x,int y,int w,int dis)
{
e[++tot].to=y;e[tot].w=w;e[tot].dis=dis;e[tot].next=head[x];head[x]=tot;
e[++tot].to=x;e[tot].w=0;e[tot].dis=-dis;e[tot].next=head[y];head[y]=tot;
}
bool spfa(int s,int t)
{
memset(dis,0x7f,sizeof(dis));
memset(flow,0x7f,sizeof(flow));
memset(vis,0,sizeof(vis));
q.push(s);vis[s]=1;dis[s]=0;pre[t]=-1;
while(!q.empty())
{
int now=q.front();q.pop();
vis[now]=0;
for(int i=head[now];i;i=e[i].next)
{
int y=e[i].to;
if(e[i].w>0&&dis[y]>dis[now]+e[i].dis)//相当于求最短路
{
dis[y]=dis[now]+e[i].dis;
pre[y]=now;
last[y]=i;
flow[y]=min(flow[now],e[i].w);
if(!vis[y])
{
vis[y]=1;q.push(y);
}
}
}
}
return pre[t]!=-1;
}
void dfs()
{
int now=t;
maxflow+=flow[t];
mincost+=flow[t]*dis[t];
while(now!=s)//从汇点一直回溯到源点
{
e[last[now]].w-=flow[t];
e[last[now]^1].w+=flow[t];
now=pre[now];
}
}
int main()
{
ios::sync_with_stdio(0);
scanf("%d",&n);
s=0,t=2*n+1;
for(int i=1;i<=n;i++)addedge(s,i,1,0),addedge(i+n,t,1,0);
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
{
scanf("%d",&m[i][j]);
addedge(i,j+n,1,m[i][j]);
}
while(spfa(s,t))dfs();
printf("%d\n",mincost);
mincost=maxflow=0;
tot=1;
memset(pre,0,sizeof(pre));
memset(last,0,sizeof(last));
memset(head,0,sizeof(head));
memset(e,0,sizeof(e));
for(int i=1;i<=n;i++)addedge(s,i,1,0),addedge(i+n,t,1,0);
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
{
addedge(i,j+n,1,-m[i][j]);
}
while(spfa(s,t))dfs();
printf("%d\n",-mincost);
return 0;
}