标签:
题意:一个矩阵中有一些点,用1*2的小矩阵覆盖这些点,求需要的最少小矩阵数;
参考:http://blog.csdn.net/lyy289065406/article/details/6647040
思路:无向图最小边覆盖数=顶点数-最大匹配数/2;
将每个待匹配的点用一个唯一的数字表示,相当于离散化,便于建图;
每个待匹配的点与相邻点建边;
由于建图是将矩阵作为二分图,一个点被拆成了两个点,因此最大匹配数要除二;
由于未匹配的点也需要覆盖,因此结果为顶点数-最大匹配数/2;
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int n,m,t,cnt; char temp; int mm[550][550]; int vis[5050],link[5005]; int mark[505][550]; int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}}; int dfs(int x) { for(int i=1;i<=cnt;i++){ if(!vis[i]&&mark[x][i]){ vis[i]=1; if(link[i]==-1||dfs(link[i])) { link[i]=x; return 1; } } } return 0; } int hungary() { int sum=0; memset(link,-1,sizeof(link)); for(int i=1;i<=cnt;i++){ memset(vis,0,sizeof(vis)); if(dfs(i)) sum++; } return sum; } int main() { int ans,i,j,k; while(scanf("%d",&t)!=EOF) { while(t--) { cnt=0; memset(mm,0,sizeof(mm)); memset(mark,0,sizeof(mark)); scanf("%d%d",&n,&m); for(i=0;i<n;i++) { for(j=0;j<m;j++) { scanf(" %c",&temp); if(temp==‘*‘){ mm[i][j]=++cnt;//每个点用数字表示 } } } for(i=0;i<n;i++) { for(j=0;j<m;j++) { if(mm[i][j]) for(k=0;k<4;k++){ int xx=i+dir[k][0]; int yy=j+dir[k][1]; if(mm[xx][yy]&&xx>=0&&yy>=0&&xx<n&&yy<m){ //相邻建边 mark[mm[xx][yy]][mm[i][j]]=1; mark[mm[i][j]][mm[xx][yy]]=1; } } } } printf("%d\n",cnt-hungary()/2); } } return 0; }
标签:
原文地址:http://www.cnblogs.com/dominating/p/4662623.html