POJ 3020 二分匹配

来源:互联网 发布:smtp端口号是多少 编辑:程序博客网 时间:2024/04/27 23:59

先建图,找最大匹配数ans

找出每个'*'  ti,ti的上下左右的‘*’与ti相连

结果为 n - ans/2

#include<cstdio>#include<cstring>using namespace std;#define M 500bool g[M][M];bool vis[M];char s[M][M];int a[M][M];int link[M];int n,r,c,ans;int nx[]={1,0,0,-1};int ny[]={0,1,-1,0};void read(){int i;for(i=0;i<r;i++){scanf("%s",s[i]);}}void init(){memset(g,0,sizeof(g));memset(a,0,sizeof(a));n=0;int i,j,k;for(i=0;i<r;i++){for(j=0;j<c;j++){if(s[i][j]=='*'){a[i][j]=++n;}}}int tx,ty;for(i=0;i<r;i++){for(j=0;j<c;j++){if(a[i][j]){for(k=0;k<4;k++){tx=i+nx[k];ty=j+ny[k];if(tx>=0&&tx<r&&ty>=0&&ty<c&&a[tx][ty]){g[ a[i][j] ][ a[tx][ty] ]=true;}}}}}}bool find(int x){int i;for(i=1;i<=n;i++){if(g[x][i]&&!vis[i]){vis[i]=true;if(link[i]==0 || find(link[i]) ){link[i]=x;return true;}}}return false;}void cal(){init();memset(link,0,sizeof(link));ans=0;int i;for(i=1;i<=n;i++){memset(vis,0,sizeof(vis));if(find(i)){ans++;}}}void answer(){printf("%d\n",n-ans/2);}int main(){int T;scanf("%d",&T);while(T--){scanf("%d%d",&r,&c);read();cal();answer();}return 0;}



原创粉丝点击