题目大意
一个长方形图由问*和o组成,每个1*2的小长方形,问几个小长方形可以覆盖全部的*
思路:
这提的难点在于建图,纠结了一天参考别人的建图方法总算才AC。
建图的时候应该给每个*的点都加上编号,之后用编号之间的的连接关系建立二分图。
建图的时候还应该注意如果两个点之间可以连接那么就两边都连上边,
刚开始想一次解决却发现由于图的关系挺复杂的,起点集终点集并不好判断。
如果不能把起点集终点集找准确,肯定是要吃WA的。
而建成这种双向边的形式只要把得到的匹配结果除以二就是真正的匹配结果了,原理也很简单。
每个参与匹配的点都作为一次起点和一次终点参与了匹配。而最小覆盖又等于最大匹配。
上面的匹配结果除以2是这个图真正的匹配数,而匹配数乘以2就是一个每个覆盖两个点的小长方形的总覆盖数。
剩下的*每个都要用一个小长方形覆盖。
#include<iostream>
#include<Cstdio>
#include<string>
using namespace std;
int map[500][500], visitY[500], useY[500];
int vis[20][50];
int h, l,sum;
int dirX[] = {1, 0, 0, -1};
int dirY[] = {0, 1, -1, 0};
bool match(int n)
{
int i;
for(i = 1; i <= sum; i++)
{
if(map[n][i] == 1 && useY[i] == -1)
{
useY[i] = 1;
if(visitY[i] == -1 || match(visitY[i]))
{
visitY[i] = n;
return true;
}
}
}
return false;
}
int Find()
{
int i, c=0, j;
for(i = 1; i <= sum; i++)
{
for(j = 1; j <= sum; j++)
useY[j] = -1;
if(match(i))
c++;
}
cout << sum - c/2 << endl;
return 0;
}
int main()
{
char temp;
int i, j, k, size, x, y;
scanf("%d", &size);
while(size--)
{
scanf("%d%d", &h, &l);
sum = 0;
for(j = 1; j <= h; j++)
{
for(i = 1; i <= l; i++)
{
cin >> temp;
vis[i][j] = -1;
if(temp == '*')
vis[i][j] = ++sum;
}
}
for(i = 1; i <= sum; i++)
for(j = 1; j <= sum; j++)
map[i][j] = -1;
for(j = 1; j <= h; j++)
{
for(i = 1; i <= l; i++)
{
if(vis[i][j] != -1)
{
for(k = 0; k < 4; k++)
{
x = i + dirX[k]; y = j + dirY[k];
if(vis[x][y] != -1)
map[vis[i][j]][vis[x][y]] = 1;
}
}
}
}
for(i = 1; i <= sum; i++)
visitY[i] = -1;
Find();
}
return 0;
}