图论——匹配

pku2594:

题意:给定一个DAG,求最少用多少条路径可以覆盖所有的点,路径可以相交。

解法:如果去掉路径可以相交这个条件的话,就是裸的求最小路径覆盖。回想求解最小路径覆盖的原理——假设开始把每个节点单独拿出来分别作为一条简单路径- -!,每增加一条匹配,就会相应的增加某条简单路径中的一个中间节点/头节点,即减少一个尾节点,即减少一条路径,那么最大匹配即是最多可已减少多少条路径,所以最小路径覆盖数=|V|-|M|(匹配数)。对于这个问题,如果我们还按那种原理计算的话——即增加一条匹配边对应增加一个头/中间 节点,那么需要先用floyd预处理一下连通性,然后就可以利用最大匹配来做了。容易证明在新图上最小路径覆盖对应的一定是一个最大匹配。

View Code
#include <iostream>
#include
<cstdio>
#include
<cstring>
usingnamespace std;

constint N =510;

int n, m, match[N];
bool visit[N], map[N][N];

void floyd()
{
int i, j, k;
for(k =1; k <= n; k++)
for(i =1; i <= n; i++)
{
if(i == k) continue;
for(j =1; j <= n; j++)
if(i!=j && j!=k)
map[i][j]
= (map[i][k] && map[k][j]) || map[i][j];
}
}

bool find(int u)
{
int i;
for(i =1; i <= n; i++)
if(map[u][i] &&!visit[i])
{
visit[i]
=true;
if(match[i]==-1|| find(match[i]))
{
match[i]
= u;
returntrue;
}
}
returnfalse;
}

int main()
{
int i, a, b, ans;
while(scanf("%d%d", &n, &m) != EOF)
{
if(n==0&& m==0) break;
memset(map,
false, sizeof(map));
for(i =0; i < m; i++)
{
scanf(
"%d%d", &a, &b);
map[a][b]
=true;
}
floyd();
ans
=0;
memset(match,
-1, sizeof(match));
for(i =1; i <= n; i++)
{
memset(visit,
false, sizeof(visit));
if(find(i)) ans++;
}
printf(
"%d\n", n-ans);
}
return0;
}

  

posted on 2011-08-11 11:00  Moon_1st  阅读(475)  评论(0编辑  收藏  举报

导航