您的位置:首页 > 其它

pku 3020 最小路径覆盖集

2011-08-09 14:58 239 查看
大概题意:用一个长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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: