洛谷 [P2825] 游戏

二分图匹配的匈牙利算法

这道题,如果没有硬石头的限制,那么就与ZJOI 2007矩阵游戏完全一样,但是如果有了硬石头的限制,我们就不能将整行整列作为元素建图,我们可以以硬石头为边界,将每一行、每一列分成若干段建图,然后跑二分图匹配即可。

这里我们总结一下类似问题的特征:

  1. 最优性问题或判定性问题
  2. 需要求出行和列的一一对应关系
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int init(){
	int rv=0,fh=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') fh=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		rv=(rv<<1)+(rv<<3)+c-'0';
		c=getchar();
	}
	return rv*fh;
}
int m,n,tot=1,tag1[55][55],tag2[55][55],g[2505][1000],match[10505];
char dt[55][55];
bool f[2505];
bool hungarian(int u){
	for(int i=1;i<=g[u][0];i++){
		int v=g[u][i];
		if(!f[v]){
			f[v]=1;
			if(!match[v]||hungarian(match[v])){
				match[v]=u;
				return 1;
			}
		}
	}
	return 0;
}
int main(){
	n=init();m=init();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf(" %c ",&dt[i][j]);
		}
	}
	for(int i=1;i<=n;i++){
		int j=1;
		while(j<=m){
			if(dt[i][j]=='#') {if(j!=1)  tot++;}
			else tag1[i][j]=tot;
			j++;
		}
		tot++;
	}
	int ma=tot-1;
	for(int j=1;j<=m;j++){
		int i=1;
		while(i<=n){
			if(dt[i][j]=='#') {if(i!=-1) tot++;}
			else tag2[i][j]=tot;
			i++;
		}
		tot++;
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(dt[i][j]=='*'){
				int a=tag1[i][j],b=tag2[i][j];
				g[a][++g[a][0]]=b;
			}
		}
	}
	int ans=0;
	for(int i=1;i<=ma;i++){
		memset(f,0,sizeof(f));
		if(hungarian(i)) ans++;
	}
	cout<<ans<<endl;
	return 0;
}
posted @ 2018-01-11 21:36  Mr_Wolfram  阅读(191)  评论(0编辑  收藏  举报