[BZOJ1143]祭祀

Posted jefflyy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ1143]祭祀相关的知识,希望对你有一定的参考价值。

这题水很深...

题目给了一个有向无环图,要求找出最多的点且这些点中不存在两个点使得它们之间有路径

如果$x$能到$y$,那么$x,y$只能选其中一个,所以连上一条边$(x,y)$不改变答案(其实是在找传递闭包)

这时可以转化一下题目:给出一个偏序集,问最大反链长度

Dilworth定理:偏序集的最大反链长度=偏序集划分为链的最少链数

这里有一篇博客写得非常好,这里引用+删减

用数学归纳法

假设偏序集为$S$且$n=\\left|S\\right|$,对于$n\\geq 2$,假设对所有的$m\\lt n$命题成立

取出$S$中的一个极大元$x$,令$S‘=S-\\left\\{x\\right\\}$

对于$S‘$,命题成立,假设它被划分成$k$条链,取$B$为每条链的最大元组成的偏序集,它是一个最大反链

①若$x$与$B$中任一元素不可比,那么它使最少链数$+1$,使最大反链长度$+1$

②若$x$与$B$中某一元素可比,因为是极大元,所以它不改变最少链数和最大反链长度

所以我们成功地把问题转化为求最小链划分

求偏序集的最小链划分是一个经典问题,可以参考这篇博客,这里引用+删减

把每个点$x$拆成$\\left(x_1,x_2\\right)$,对于每条原图中的边$(x,y)$,在新图中连边$\\left(x_1,y_2\\right)$

设$match$为新图的最大匹配数,答案$=n-match$

原理是匹配一条边相当于连接两条链(答案$-1$),因为是划分(链不可相交)所以对应到新图中匹配边不可相交

然后就做完了

总的过程:先用Warshall算法求出传递闭包,再建二分图用匈牙利算法跑匹配,答案是节点数减去匹配数

代码很短,但背后蕴含的思想较为恐怖

原来离散数学前几章不是一点用都没有啊

#include<stdio.h>
#include<string.h>
bool g[110][110],v[110];
int n,link[110];
bool hungary(int x){
	for(int i=1;i<=n;i++){
		if(g[x][i]&&!v[i]){
			v[i]=1;
			if(link[i]==-1||hungary(link[i])){
				link[i]=x;
				return 1;
			}
		}
	}
	return 0;
}
int match(){
	int i,s=0;
	memset(link,-1,sizeof(link));
	for(i=1;i<=n;i++){
		memset(v,0,sizeof(v));
		if(hungary(i))s++;
	}
	return s;
}
int main(){
	int m,i,j,k;
	scanf("%d%d",&n,&m);
	while(m--){
		scanf("%d%d",&i,&j);
		g[i][j]=1;
	}
	for(k=1;k<=n;k++){
		for(i=1;i<=n;i++){
			for(j=1;j<=n;j++)g[i][j]=g[i][j]||(g[i][k]&&g[k][j]);
		}
	}
	printf("%d",n-match());
}

以上是关于[BZOJ1143]祭祀的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ1143 [CTSC2008] 祭祀river

bzoj1143[CTSC2008]祭祀river

bzoj 1143: [CTSC2008]祭祀river

[bzoj1143]祭祀

[BZOJ1143]祭祀

bzoj1143: [CTSC2008]祭祀river 最长反链