题目传送门
最小费用最大流,最大费用最大流
源点与人相连,流量为1,费用0
汇点与物件相连,流量为1,费用为0
人与物件相连,流量为1,费用为c[i][j]
最大费用最大流转换成最小费用最大流,方法就是建图的时候把费用变成相反数跑最小费用最大流,最后答案取相反数即可
#include
#include
#include
#include
#include
#define inf 1000000007
using namespace std;
int head[30001],nxt[30001],to[30001],flow[30001],value[30001],tot=1;
int from[30001],pre[30001],dis[30001],vis[30001];
int n;
int st,lt;
int ansflow,anscost;
int c[101][101];
queue<int>q;
void add(int x,int y,int f,int v)
{
tot++;
nxt[tot]=head[x];
head[x]=tot;
to[tot]=y;
flow[tot]=f;
value[tot]=v;
pre[tot]=x;
return;
}
bool spfa(int s)
{
for(int i=1;i<=n*2+10;i++)
dis[i]=inf;
memset(vis,0,sizeof(vis));
vis[s]=1;
dis[s]=0;
q.push(s);
while(!q.empty())
{
int x=q.front();
q.pop();
vis[x]=0;
for(int i=head[x];i;i=nxt[i])
{
int p=to[i];
if(flow[i]>0&&dis[p]>dis[x]+value[i])
{
from[p]=i;
dis[p]=dis[x]+value[i];
if(!vis[p])
{
q.push(p);
vis[p]=1;
}
}
}
}
if(dis[lt]>=inf)return 0;
else return 1;
}
void mcmf()
{
int x=inf;
for(int i=from[lt];i;i=from[pre[i]])
{
x=min(x,flow[i]);
}
ansflow+=x;
for(int i=from[lt];i;i=from[pre[i]])
{
flow[i]-=x;
flow[i^1]+=x;
anscost+=value[i]*x;
}
return;
}
int main()
{
scanf("%d",&n);
st=n*2+3;
lt=n*2+10;
for(int i=1;i<=n;i++)
{
add(st,i,1,0);
add(i,st,0,0);
add(i+n,lt,1,0);
add(lt,i+n,0,0);
}
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]);
}
while(spfa(st))
{
mcmf();
}
printf("%d",anscost);
memset(head,0,sizeof(head));
memset(from,0,sizeof(from));
tot=1;
anscost=0;
for(int i=1;i<=n;i++)
{
add(st,i,1,0);
add(i,st,0,0);
add(i+n,lt,1,0);
add(lt,i+n,0,0);
}
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]);
}
while(spfa(st))
{
mcmf();
}
printf("\n%d",-anscost);
return 0;
}