九野的博客,转载请注明出处:http://blog.youkuaiyun.com/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 51
using 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;
}
/*
2
7 9
ooo**oooo
**oo*ooo*
o*oo**o**
ooooooooo
*******oo
o*o*oo*oo
*******oo
10 1
*
*
*
o
*
*
*
*
*
*
*/