pku 3020 最小路径覆盖集

大概题意:用一个长2宽1的面积去覆盖图中所有的'*',面积间可以重叠。更简单的,就是用最少的连接两个相邻点的边,连接起图中所有的'*'。复杂的问题变成了最小路径覆盖

分析:最小路径覆盖=所有的点数-最大独立集,而最大独立集就等于最大匹配数。再分析,这是一个无向图,A点连着B点,B点也同时连着A点。于是求的的最大匹配数是原匹配数的两倍,对于本题,最终答案为:所有'*'数-最大匹配数/2。

也可以总结如下:

对于有向图,最大独立集等于最大匹配数

对于无向图,最大独立集等于最大匹配数/2

建图:对每个'*'给一个号码,由于面积是1*2的,所有每个'*'只能和它四周的'*'相连,根据这个原则建图,然后对所有的'*'求最大匹配,按上面的分析输出答案即可

View Code
#include<iostream>
#include
<string>
using namespace std;

int map[405][405];
int link[405];
char graph[42][12];
int n,m;
int v[405];
int num[42][12];
int cut;
int di[4][2]={1,0,0,1,-1,0,0,-1};

int find(int x)
{
for(int i=1;i<=cut;i++)
{
if(!v[i] && map[x][i])
{
v[i]
=1;
if(link[i]==0 || find(link[i]))
{
link[i]
=x;
return 1;
}
}
}
return 0;
}

int solve()
{
int ans=0;
memset(link,
0,sizeof(link));
for(int i=1;i<=cut;i++)
{
memset(v,
0,sizeof(v));
if(find(i))
ans
++;
}
return ans;
}

int main()
{
int i,j,t,k;
freopen(
"D:\\in.txt","r",stdin);
scanf(
"%d",&t);
while(t--)
{
cut
=0;
memset(num,
0,sizeof(num));
scanf(
"%d%d%*c",&n,&m);
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
scanf(
"%c",&graph[i][j]);
if(graph[i][j]=='*')
{
num[i][j]
=++cut;
}
}
scanf(
"%*c");
}
int x,y;
memset(map,
0,sizeof(map));
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
for(k=0;k<4;k++)
{
if(graph[i][j]=='*')
{
x
=i+di[k][0];
y
=j+di[k][1];
if(x>0 && x<=n && y>0 && y<=m && graph[x][y]=='*')
{
map[num[i][j]][num[x][y]]
=1;
}
}
}
}
}
int ans=solve();
cout
<<cut-ans/2<<endl;
}
return 0;
}
原文地址:https://www.cnblogs.com/ka200812/p/2132292.html