【bzoj1143: [CTSC2008]祭祀river】有向无环图的最长反链
2017-12-03 14:20
369 查看
1143: [CTSC2008]祭祀river
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3192 Solved: 1632
[Submit][Status][Discuss]
Description
在遥远的东方,有一个神秘的民族,自称Y族。他们世代居住在水面上,奉龙王为神。每逢重大庆典, Y族都会在水面上举办盛大的祭祀活动。我们可以把Y族居住地水系看成一个由岔口和河道组成的网络。每条河道连接着
两个岔口,并且水在河道内按照一个固定的方向流动。显然,水系中不会有环流(下图描述一个环流的例子)。
由于人数众多的原因,Y族的祭祀活动会在多个岔口上同时举行。出于对龙王的尊重,这些祭祀地点的选择必
须非常慎重。准确地说,Y族人认为,如果水流可以从一个祭祀点流到另外一个祭祀点,那么祭祀就会失去它神圣
的意义。族长希望在保持祭祀神圣性的基础上,选择尽可能多的祭祀的地点。
Input
第一行包含两个用空格隔开的整数N、M,分别表示岔口和河道的数目,岔口从1到N编号。接下来M行,每行包含两个用空格隔开的整数u、v,描述一条连接岔口u和岔口v的河道,水流方向为自u向v。 N ≤ 100 M ≤ 1 000
Output
第一行包含一个整数K,表示最多能选取的祭祀点的个数。Sample Input
4 41 2
3 4
3 2
4 2
Sample Output
2【样例说明】
在样例给出的水系中,不存在一种方法能够选择三个或者三个以上的祭祀点。包含两个祭祀点的测试点的方案有两种:
选择岔口1与岔口3(如样例输出第二行),选择岔口1与岔口4。
水流可以从任意岔口流至岔口2。如果在岔口2建立祭祀点,那么任意其他岔口都不能建立祭祀点
但是在最优的一种祭祀点的选取方案中我们可以建立两个祭祀点,所以岔口2不能建立祭祀点。对于其他岔口
至少存在一个最优方案选择该岔口为祭祀点,所以输出为1011。
icpc上居然出了这个原题,就爆炸了,回来补一补二分图和有向无环图的东西。
1、二分图最大匹配
匈牙利算法O(V*E)的复杂度内可求出二分图的最大匹配
2、二分图最小点覆盖
找到点数最少的一个点集,使得二分图里的所有边至少有一个端点是在该点集中
最小点覆盖=最大匹配
3、二分图最小边覆盖
找到边数最少的一个边集,使得二分图里的所有点至少是一条边的端点
最小边覆盖=图中点的个数-最大匹配
证明:把最大匹配的边都加入,则剩下的点之间都没有边,那么再把剩下的点都连接起来,边数=最大匹配+图中点的个数-2*最大匹配=图中点的个数-最大匹配
4、二分图最大独立集
找到一个点数最大的点集,使得点集里的所有点对之间在原图里没有边。
最大独立集=图中点的个数-最大匹配
证明:把所有点加入点集中,最大独立集问题就转化为删去最少的点使得最终的点集是个独立集,那么 最大独立集=图中点的个数-最小点覆盖=图中点的个数-最大匹配
最小不相交路径覆盖:每一条路径经过的顶点各不相同。如,最小路径覆盖数为3:1->3>4,2,5。
最小可相交路径覆盖:每一条路径经过的顶点可以相同。如,最小路径覆盖数为2,1->3->4,2->3>5。
5、有向无环图最小不相交路径覆盖
用最少的不相交路径覆盖所有顶点。
将有向无环图中的各点拆点,i点拆为ai,bi ,对于一条边:i->j,转化为 ai->bj, 便可把有向无环图转化为二分图。
有向无环图最小不相交路径覆盖=图中点的个数-最大匹配
证明:刚开始每个点为一条路径,则开始时有n条路径,对于二分图中的每一条匹配边就代表把两条路径变为一条路径,则最后的答案就是图中点的个数-最大匹配
6、有向无环图最小可相交路径覆盖
用最少的可相交路径覆盖所有顶点。
处理出有向无环图中所有点的到达情况,拆点,若i点可经过一条路径到达j点,那么连一条ai->bj 的边,此时有向图边转化为二分图,问题也就转化为5、有向无环图最小不相交路径覆盖。
在有向无环图中,有如下的一些定义和性质:
链:一条链是一些点的集合,链上任意两个点x, y,满足要么
x 能到达
y ,要么
y 能到达
x 。
反链:一条反链是一些点的集合,链上任意两个点x, y,满足
x 不能到达
y,且
y 也不能到达
x。
一个定理:最长反链长度 =
最小链覆盖(用最少的链覆盖所有顶点)
对偶定理:最长链长度 =
最小反链覆盖 ///????这个是什么意思没看懂,有人看懂了评论下
最小链覆盖也就是最小可相交路径覆盖。
经过上面一些乱七八糟的介绍,可以知道,这道题目就是求最长反链长度,就是求最长反链长度,就是求有向无环图最小可相交路径覆盖,见(6)
求各点的联通性可以用Floyd 也可以直接搜。
#include<cstdio>
#include<cstring>
#define M 1005
#define N 105
using namespace std;
int k,K,fir
,Fir
,n,m,l,r,sign
,link
,vis
;
struct he{
int r,nx;
}A[N*N],a[M];
void add(int l,int r){
k++;a[k].r=r;a[k].nx=fir[l];fir[l]=k;
}
void Add(int l,int r){
K++;A[K].r=r;A[K].nx=Fir[l];Fir[l]=K;
}
void dfs(int x,int f){
vis[x]=1;
if(x!=f)Add(f,x);
for(int i=fir[x];i!=-1;i=a[i].nx)
if(!vis[a[i].r]){
dfs(a[i].r,f);
}
}
bool check(int x){
for(int i=Fir[x];i!=-1;i=A[i].nx)
if(!sign[A[i].r]){
sign[A[i].r]=1;
if(link[A[i].r]==0){
link[A[i].r]=x;
return true;
}
if(check(link[A[i].r])){
link[A[i].r]=x;
return true;
}
}
return false;
}
int hungery(){
int ans=n;
for(int i=1;i<=n;i++){
memset(sign,0,sizeof(sign));
if(check(i)) ans--;
}
return ans;
}
int main(){
memset(fir,-1,sizeof(fir));
memset(Fir,-1,sizeof(Fir));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&l,&r);
add(l,r);
}
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
dfs(i,i);
}
printf("%d",hungery());
}
相关文章推荐
- 最长反链(bzoj 1143: [CTSC2008]祭祀river)
- BZOJ 1143: [CTSC2008]祭祀river 最长反链
- BZOJ 1143 1143: [CTSC2008]祭祀river 最长反链
- 【BZOJ1143】[CTSC2008]祭祀river【最长反链】【传递闭包】
- bzoj 1143: [CTSC2008]祭祀river 求最长反链:网络流
- [BZOJ1143][CTSC2008]祭祀river(最长反链)
- [BZOJ 1143] [CTSC2008] 祭祀river 【最长反链】
- 2718: [Violet 4]毕业旅行/1143: [CTSC2008]祭祀river 最长反链=最小边覆盖
- bzoj2718/1143 CTSC2008 祭祀 最长反链
- [BZOJ1143]CTSC2008祭祀|最长反链|floyd|二分图匹配
- BZOJ.1143.[CTSC2008]祭祀(最长反链 最大流ISAP)
- 【BZOJ】1143: [CTSC2008]祭祀river
- bzoj1143 [CTSC2008]祭祀river
- 【CTSC2008】【BZOJ1143】祭祀river
- BZOJ 1143: [CTSC2008]祭祀river 二分图,最大独立集,Floyd闭包
- 【BZOJ 1143】[CTSC2008]祭祀river
- [1143] [CTSC2008]祭祀river(最大独立集 || 偏序集最大反链)
- BZOJ 1143: [CTSC2008]祭祀river 二分图最大点独立集
- [BZOJ]1143: [CTSC2008]祭祀river 二分图匹配
- BZOJ 1143: [CTSC2008]祭祀river