题目描述:
给你一个n个点m条边的有向无环图,求出最大点集满足其中任意两点间都不能存在路径
也就是对于所有的x, y∈S,x不能到达y,y也不能到达x
对于有向无环图(DAG):
链:一些点的集合,链中任意两点x, y,一定满足x能到达y或者y能到达x
反链:一些点的集合,链中任意两点x, y,一定满足x不能到达y,y也不能到达x
而上题显然就是求出最长反链
定理:最长反链 = 最小链覆盖(用最少的链覆盖图中所有的点,即路径可重叠的最小路径覆盖)
这样题目就又转成了求可重叠的最小路径覆盖
对于二分图:
最小点覆盖(每条边都有至少一个点在集合中)= 最大匹配
最小边覆盖(每个点都有至少一个连它的边在集合里 ,如果某点没有边相连就直接+1)= 二分图点数 - 最大匹配
最大独立集(集合中任意两点之间都没有边)= 二分图点数 - 最大匹配
DAG的最小路径覆盖:
将原图的每个点拆成xa,xb两个,分别在二分图的两边,如果原图存在有向边x->y,那么xa到yb连一条边
那么DAG最小路径覆盖(路径不可重叠的) = 原图点数 - 最大匹配
证明:
开始每个点都独立为一条路径,总共有n条不相交路径,在二分图里每加一条边就相当于将两条路径合成了一条
如果二分图中两条边有公共点,那么这两条边就相当于原图中两条到同一个点的边或者从同一个点引出的两条边
显然这两条边一定属于不同路径!
所以说DAG中最小不可重叠路径覆盖可以通过转成二分图求出
而题目中要求的是最小可重叠路径覆盖
那怎么办?
其实很简单,改一下只要x能到达y,那么xa到yb连一条边再求一遍最大匹配就ok了
floyd+二分匹配搞定,复杂度O(n^3)
1143: [CTSC2008]祭祀river
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3132 Solved: 1606
[ Submit][ Status][ Discuss]
Description
Input
Output
第一行包含一个整数K,表示最多能选取的祭祀点的个数。
Sample Input
Sample Output
就是上面例子那道题
#include<stdio.h>
#include<string.h>
int n, road[105][105], link[105], vis[105];
int Sech(int x)
{
int i;
for(i=1;i<=n;i++)
{
if(road[x][i] && vis[i]==0)
{
vis[i] = 1;
if(link[i]==0 || Sech(link[i]))
{
link[i] = x;
return 1;
}
}
}
return 0;
}
int main(void)
{
int i, j, k, m, x, y, ans;
scanf("%d%d", &n, &m);
for(i=1;i<=m;i++)
{
scanf("%d%d", &x, &y);
road[x][y] = 1;
}
for(k=1;k<=n;k++)
{
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(road[i][k] && road[k][j])
road[i][j] = 1;
}
}
}
ans = 0;
for(i=1;i<=n;i++)
{
memset(vis, 0, sizeof(vis));
ans += Sech(i);
}
printf("%d\n", n-ans);
return 0;
}