BZOJ4883 [Lydsy2017年5月月賽]棋盤上的守衛

本文版權歸ljh2000和博客園共有,歡迎轉載,但須保留此聲明,並給出原文連接,謝謝合做。php

 

 

本文做者:ljh2000
做者博客:http://www.cnblogs.com/ljh2000-jump/
轉載請註明出處,侵權必究,保留最終解釋權!ios

 

 

題目連接:BZOJ4883spa

正解:貪心blog

解題報告:get

  又是用貪心模擬費用流…博客

  考慮直接跑費用流,複雜度很不靠譜,那麼用以前$get$的姿式:用貪心模擬費用流。string

  費用流建圖的話很是$simple$,若是咱們用相似最小生成樹的方式,把邊按邊權從小到大往裏面加。it

  咱們觀察一下費用流建的那張圖,一次增廣,本質上能夠當作是選擇了一個行編號和一個列編號,那麼咱們考慮每一個點加入時的狀況。至關因而每一個行、列所表明的點的入度強制要爲1,那麼只有多是帶一個環的樹;若是圖是一棵樹,那麼必然能夠匹配;若是是一棵n條邊的基環樹,那麼也能匹配。分類討論,除非兩個都爲圖,不然就能匹配。按最小生成樹的方式作就行了。io

 

 

//It is made by ljh2000
//有志者,事竟成,破釜沉舟,百二秦關終屬楚;苦心人,天不負,臥薪嚐膽,三千越甲可吞吳。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <cmath>
#include <ctime>
#define lc root<<1
#define rc root<<1|1
#define reg(i,x) for(int i=first[x];i;i=nxt[i])
using namespace std;
typedef long long LL;
const int MAXN = 200011;
int n,m,cnt,fa[MAXN];
bool G[MAXN];
LL ans;
struct edge{ int x,y,z; }e[MAXN];
inline bool cmp(edge q,edge qq){ return q.z<qq.z; }
inline int find(int x){ if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; }
inline void link(int x,int y,int z){ e[++cnt].x=x; e[cnt].y=y; e[cnt].z=z; }
inline int getint(){
    int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
    if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
}

inline void work(){
	n=getint(); m=getint(); int x,y,z;
	for(int i=n+m;i>=1;i--) fa[i]=i;
	for(int i=1;i<=n;i++) 
		for(int j=1;j<=m;j++) {
			z=getint();
			link(i,j+n,z);
		}
	sort(e+1,e+cnt+1,cmp);
	for(int i=1;i<=cnt;i++) {
		x=find(e[i].x); y=find(e[i].y);
		if(G[x] && G[y]) continue;
		if(x!=y){
			fa[x]=y;
			G[y]|=G[x];
		}
		else G[y]=1;
		ans+=e[i].z;		 
	}		
	printf("%lld",ans);
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("4883.in","r",stdin);
	freopen("4883.out","w",stdout);
#endif
    work();
    return 0;
}
//有志者,事竟成,破釜沉舟,百二秦關終屬楚;苦心人,天不負,臥薪嚐膽,三千越甲可吞吳。
相關文章
相關標籤/搜索