POJ 3020 最小路径覆盖 = 顶点数-最大匹配数 二分匹配

来源:互联网 发布:ant运行java文件 编辑:程序博客网 时间:2024/06/07 05:10

九野的博客,转载请注明出处:http://blog.csdn.net/acmmmm/article/details/12841003

题意:

t个测试数据, n*m 的矩阵

用1*2的格子覆盖 所有 *   (1*2格子可重叠) 问最少需要多少个

 

此题和1507同出一辙,修改一下就可以了, 图中'O' 相当于1507中的坏点

答案则是1507的答案加上未使用的白点数

 

注意因为建的是无向二分图,最大匹配数结果是翻倍的

 

#include<stdio.h>#include<string.h>#include<algorithm>#include<vector>#define N 60#define M 51using namespace std;int map[N][N];int n,m;int lef[N*N], pn;//lef[v]表示Y集的点v 当前连接的点  bool T[N*N];     //T[u] 表示Y集 u 是否已连接X集vector<int>G[N*N]; //匹配边  G[X集].push_back(Y集)  注意G 初始化bool match(int x){ // x和Y集 匹配 返回x点是否匹配成功for(int i=0; i<G[x].size(); i++){int v = G[x][i];if(!T[v]){T[v] = true;if(lef[v] == -1 || match( lef[v] ))   //match(lef[v]) : 原本连接v的X集点 lef[v] 能不能和别人连,如果能 则v这个点就空出来和x连{lef[v] = x;return true;}}}return false;}int solve(){int ans = 0;memset(lef, -1, sizeof(lef));for(int i = 1; i<= n; i++)//X集匹配,X集点标号从 1-pn 匹配边是G[左点].size()   for(int j = 1; j<=m; j++)if(map[i][j]){memset(T, 0, sizeof(T));if( match( i*M + j ) ) ans++;}return ans;}void zouni(int x,int y,int x1,int y1){if(x1>n || y1>m || x>n || y>m)return ;if(map[x1][y1]==0 || map[x][y] == 0)return ;G[x*M+y].push_back(x1*M+y1);}void Have_map(){for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++)if(map[i][j]){zouni(i,j,i+1,j);zouni(i,j,i,j+1);zouni(i+1,j,i,j);zouni(i,j+1,i,j);}}void init(){for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++)G[i*M+j].clear();}char s[N];int main(){int i,j,t;scanf("%d",&t);while(t--){int point=0;memset(map,0,sizeof(map));init();scanf("%d %d",&n,&m);getchar();for(i=1;i<=n;i++){scanf("%s",s);for(j=0;j<m;j++)if(s[j]=='*')map[i][j+1]=1,point++;}Have_map();int zz=solve();printf("%d\n",point - (zz>>1));}return 0;}/*27 9ooo**oooo**oo*ooo*o*oo**o**ooooooooo*******ooo*o*oo*oo*******oo10 1***o*******/


 

原创粉丝点击