洛谷 [P2825] 游戏
二分图匹配的匈牙利算法
这道题,如果没有硬石头的限制,那么就与ZJOI 2007矩阵游戏完全一样,但是如果有了硬石头的限制,我们就不能将整行整列作为元素建图,我们可以以硬石头为边界,将每一行、每一列分成若干段建图,然后跑二分图匹配即可。
这里我们总结一下类似问题的特征:
- 最优性问题或判定性问题
- 需要求出行和列的一一对应关系
#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;
}