链接:点击打开链接
题意:给出一个N*M的棋盘,现在给出K个位置可以放棋子,现要求每行每列最多放一个棋子,求最多放的棋子个数,并输出所有达到最多棋子个数的可能中相同位置的棋子个数
代码:
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m;
int fa[105],vis[105];
int x[10005],y[10005];
int s[105][105],op[105][105];
int dfs(int S){
int i,j;
for(i=1;i<=m;i++){
if(vis[i]==0&&s[S][i]&&op[S][i]==0){
vis[i]=1;
if(fa[i]==-1||dfs(fa[i])){
fa[i]=S;
return 1;
}
}
}
return 0;
}
int main(){
int i,j,k,ans,sum,cas=1,tmp;
while(scanf("%d%d%d",&n,&m,&k)!=EOF){
memset(s,0,sizeof(s));
for(i=1;i<=k;i++){
scanf("%d%d",&x[i],&y[i]);
s[x[i]][y[i]]=1;
}
ans=sum=0;
memset(op,0,sizeof(op));
memset(fa,-1,sizeof(fa));
for(i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
if(dfs(i))
ans++;
} //把行和列变成点,能放的点就把行和列连起来
for(i=1;i<=k;i++){ //求二分图最大匹配就是最多能放的棋子数,这
memset(fa,-1,sizeof(fa)); //还是比较基础的,但是在于怎么求相同的点的
op[x[i]][y[i]]=1; //个数,因为每一条边相当于一个点,我们可以
tmp=0; //枚举删除每一条边,看二分图匹配的值是否会变
for(j=1;j<=n;j++){ //这题数据比较水,用匈牙利的话复杂度是O(n*k*k)
memset(vis,0,sizeof(vis)); //用网络流的话复杂度可以变为O(n*k*log(k))
if(dfs(j))
tmp++;
}
if(tmp!=ans)
sum++;
op[x[i]][y[i]]=0;
}
printf("Board %d have %d important blanks for %d chessmen.\n",cas++,sum,ans);
}
return 0;
}