BZOJ 4883 [Lydsy2017年5月月賽]棋盤上的守衛(最小生成環套樹森林)
阿新 • • 發佈:2017-05-06
print 我們 size -s nbsp long pan typedef 包含
所以題目就轉化成求圖中的最小生成環套樹森林。
【題目鏈接】 http://www.lydsy.com/JudgeOnline/problem.php?id=4883
【題目大意】
在一個n*m的棋盤上要放置若幹個守衛。
對於n行來說,每行必須恰好放置一個橫向守衛;同理對於m列來說,
每列必須恰好放置一個縱向守衛。每個位置放置守衛的代價是不一樣的,
且每個位置最多只能放置一個守衛,一個守衛不能同時兼顧行列的防禦。
請計算控制整個棋盤的最小代價。
【題解】
我們將每行和每列看成一個點,用每個格子上的點的權值作為邊,
這就構成了一個n+m個點的圖。
我們發現對於n個點的集合,為了滿足題目中的要求,就至少要包含n條邊。
所以題目就轉化成求圖中的最小生成環套樹森林。
【代碼】
#include <cstdio> #include <algorithm> using namespace std; typedef long long LL; const int N=200010; LL ans; int x,n,m,f[N],v[N]; struct E{int u,v,c;E(){}E(int u,int v,int c):u(u),v(v),c(c){};}e[N]; bool cmp(E x,E y){return x.c<y.c;} int sf(int x){return x==f[x]?x:f[x]=sf(f[x]);} int main(){ while(~scanf("%d%d",&n,&m)){ int cnt=ans=0; for(int i=1;i<=n+m;i++)f[i]=i,v[i]=0; for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){ scanf("%d",&x); e[++cnt]=E(i,j+n,x); }sort(e+1,e+cnt+1,cmp); for(int i=1;i<=cnt;i++){ int fx=sf(f[e[i].u]),fy=sf(f[e[i].v]); if(v[fx]&&v[fy])continue; if(fx!=fy)v[fy]|=v[fx],f[fx]=fy;else v[fx]=1; ans+=e[i].c; }printf("%lld\n",ans); }return 0; }
BZOJ 4883 [Lydsy2017年5月月賽]棋盤上的守衛(最小生成環套樹森林)