题意:
在一个n*m的棋盘上要放置若干个守卫。对于n行来说,每行必须恰好放置一个横向守卫;同理对于m列来说,每列必须恰好放置一个纵向守卫。每个位置放置守卫的代价是不一样的,且每个位置最多只能放置一个守卫,一个守卫不能同时兼顾行列的防御。请计算控制整个棋盘的最小代价。
题解:
第一次见到这种题……太菜了。
一眼费用流,n*m个点向行列连边,稳T。
%题解,发现是最小环套树森林。
i行,j列间连边,边权为w[i][j],那么相当于要选出n+m条有向边,是每个点出度为1,显然是一个环套树森林。
求这个东西跟kruskal差不多,多记录一下当前联通块是否有环。
code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
struct node{
int x,y,c;
}a[100010];int len=0;
int n,m,fa[100010],vis[100010];
bool cmp(node a,node b) {return a.c<b.c;}
int findfa(int x) {return fa[x]==x?x:fa[x]=findfa(fa[x]);}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int c;scanf("%d",&c);
a[++len].x=i;a[len].y=j+n;a[len].c=c;
}
sort(a+1,a+len+1,cmp);
for(int i=1;i<=n+m;i++) fa[i]=i,vis[i]=0;
LL ans=0;
for(int i=1;i<=len;i++)
{
int x=findfa(a[i].x),y=findfa(a[i].y);
if(vis[x]&&vis[y]) continue;
if(x==y) vis[x]=1;
else fa[x]=y,vis[y]|=vis[x];
ans+=a[i].c;
}
printf("%lld",ans);
}