图论——匹配
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;
}