这道题想了很久,预先知道是匈牙利算法,但是呢,实在没法和二分图联系起来,尤其是怎么想最大点集覆盖和最大匹配都不行。
磨蹭两个小时,跑去看答案,小优的答案很详细,大家自己看吧:
http://blog.csdn.net/lyy289065406/article/details/6647040
基本的思想是:
无向二分图的最小路径覆盖 = 顶点数 – 最大二分匹配数/2
构造一个无向二分图,然后利用匈牙利算法,公式,主要在于二分图的构造上,小优说得很详细,但是我不是很懂其实。一次AC。
//poj3020
#include <iostream>
using namespace std;
int grid[50][20];
int map[1000][1000];
int visit[10000];
int link[1000];
int m;
bool dfs(int x, int n)
{
for (int i = 1; i <= n; i++)
{
if (map[x][i] == 1 && !visit[i])
{
visit[i] = true;
if(link[i] == 0 || dfs(link[i], n))
{
link[i] = x;
return true;
}
}
}
return false;
}
int search(int n)
{
for (int i = 1; i <= n; i++)
{
memset(visit, 0, sizeof(visit));
if (dfs(i, n))
m++;
}
return m;
}
int main()
{
int n;
cin >> n;
while (n--)
{
memset(grid, 0, sizeof(grid));
memset(map, 0, sizeof(map));
memset(link, 0, sizeof(link));
int a, b;
cin >> a >> b;
int num = 0;
char c;
m = 0;
for (int i = 0; i < a; i++)
{
for (int j = 0; j < b; j++)
{
cin >> c;
if (c == '*')
{
num++;
grid[i][j] = num;
}
else
grid[i][j] = 0;
}
}
for (int i = 0; i < a; i++)
{
for (int j = 0; j < b; j++)
{
if (grid[i][j])
{
if (i - 1 >= 0 && grid[i - 1][j])
{
map[grid[i][j]][grid[i - 1][j]] = 1;
map[grid[i - 1][j]][grid[i][j]] = 1;
}
if (i + 1 < a && grid[i + 1][j])
{
map[grid[i][j]][grid[i + 1][j]] = 1;
map[grid[i + 1][j]][grid[i][j]] = 1;
}
if (j - 1 >= 0 && grid[i][j - 1])
{
map[grid[i][j]][grid[i][j - 1]] = 1;
map[grid[i][j - 1]][grid[i][j]] = 1;
}
if (j + 1 < b && grid[i][j + 1])
{
map[grid[i][j]][grid[i][j + 1]] = 1;
map[grid[i][j + 1]][grid[i][j]] = 1;
}
}
}
}
int mapnum = search(num);
cout << num - mapnum / 2<< endl;
}
return 0;
}