bzoj 4883: [Lydsy2017年5月月赛]棋盘上的守卫 最小生成树
2017-05-09 20:33
417 查看
题意
在一个n*m的棋盘上要放置若干个守卫。对于n行来说,每行必须恰好放置一个横向守卫;同理对于m列来说,每列必须恰好放置一个纵向守卫。每个位置放置守卫的代价是不一样的,且每个位置最多只能放置一个守卫,一个守卫不能同时兼顾行列的防御。请计算控制整个棋盘的最小代价。2<=n,m<=100000,n*m<=100000
分析
首先很直观的想法就是费用流(据说可以大力艹过去),但复杂度毕竟是玄学。我们把一个点看成一条连接其所在行和所在列的边,那么我们就要找到一个子图,使得我们把所有边定向后每个点的入度恰好为1且权值和最小。那么就只要求一个带环的最小生成森林即可。
代码
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; typedef long long LL; const int N=100005; int n,m,cnt,f[N*2],vis[N*2]; struct edge{int x,y,len;}e[N*3]; bool cmp(edge a,edge b) { return a.len<b.len; } int find(int x) { if (f[x]==x) return x; f[x]=find(f[x]); return f[x]; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { int x; scanf("%d",&x); e[++cnt].x=i;e[cnt].y=j+n;e[cnt].len=x; } sort(e+1,e+cnt+1,cmp); for (int i=1;i<=n+m;i++) f[i]=i; LL ans=0; for (int i=1;i<=cnt;i++) { int x=find(e[i].x),y=find(e[i].y); if (x==y) { if (!vis[x]) vis[x]=1,ans+=e[i].len; } else if (!vis[x]||!vis[y]) f[x]=y,vis[y]|=vis[x],ans+=e[i].len; } printf("%lld",ans); return 0; }
相关文章推荐
- [BZOJ 4883][Lydsy2017年5月月赛]棋盘上的守卫:最小生成树
- BZOJ 4883 [Lydsy2017年5月月赛]棋盘上的守卫(最小生成环套树森林)
- 【bzoj4883】[Lydsy2017年5月月赛]棋盘上的守卫 最小环套树森林
- 【BZOJ4883】[Lydsy2017年5月月赛]棋盘上的守卫 KM算法
- bzoj4883 [Lydsy2017年5月月赛]棋盘上的守卫
- BZOJ4883 [Lydsy2017年5月月赛]棋盘上的守卫
- BZOJ4883: [Lydsy2017年5月月赛]棋盘上的守卫
- bzoj 4883: [Lydsy2017年5月月赛]棋盘上的守卫
- [bzoj4883][Lydsy2017年5月月赛]棋盘上的守卫
- 4883: [Lydsy2017年5月月赛]棋盘上的守卫
- BZOJ4883 [Lydsy2017年5月月赛]棋盘上的守卫
- bzoj 4881: [Lydsy2017年5月月赛]线段游戏 树状数组+set
- [bzoj4881][Lydsy2017年5月月赛]线段游戏
- bzoj4886 [Lydsy2017年5月月赛]叠塔游戏
- bzoj 4878 [Lydsy2017年5月月赛]挑战NP-Hard(dfs)
- BZOJ 4881 [Lydsy2017年5月月赛] 二分图染色+线段树
- 【bzoj4883】棋盘上的守卫 题解
- bzoj 4885: [Lydsy2017年5月月赛]长方体
- BZOJ 4884 [Lydsy2017年5月月赛]太空猫(单调DP)
- bzoj4885: [Lydsy2017年5月月赛]长方体