[BZOJ 1143] [CTSC2008] 祭祀river 【最长反链】

题目链接:BZOJ - 1143

题目分析

这道题在BZOJ上只要求输出可选的最多的祭祀地点个数,是一道求最长反链长度的裸题。

下面给出一些相关知识:

在有向无环图中,有如下的一些定义和性质:

链:一条链是一些点的集合,链上任意两个点x, y,满足要么 x 能到达 y ,要么 y 能到达 x 。

反链:一条反链是一些点的集合,链上任意两个点x, y,满足 x 不能到达 y,且 y 也不能到达 x。

那么很显然这道题就是求最长反链长度了。

一个定理:最长反链长度 = 最小链覆盖(用最少的链覆盖所有顶点)

对偶定理:最长链长度 = 最小反链覆盖

那么我们要求出的就是这个有向无环图的最小链覆盖了。最小链覆盖也就是路径可以相交的最小路径覆盖。

我们先来看路径不能相交的最小路径覆盖怎么来做:

建立一个二分图,两边都是n个点,原图的每个点 i 对应两个,在左边的叫做 i1, 在右边的叫做 i2 。

然后原图中如果存在一条边 (x, y),那么就在二分图中建立 (x1, y2) 的边。

这样建立二分图之后,原图的点数 n - 二分图最大匹配 = 原图的最小路径覆盖(路径不能相交)。

这样为什么是对的呢?我们可以认为,开始时原图的每个点都是独立的一条路径,然后我们每次在二分图中选出一条边,就是将两条路径连接成一条路径,答案数就减少1。

而路径是不能相交的,所以我们在二分图中选出的边也是不能相交的,所以就是二分图的最大匹配。

了解了路径不能相交的最小路径覆盖之后,怎么解路径可以相交的最小路径覆盖(也就是最小链覆盖)呢?

我们将原图做一次Floyd传递闭包,之后就可以知道任意两点 x, y,x 是否能到达 y。

如果两个点 x, y,满足 x 可以到达 y ,那么就在二分图中建立边 (x1, y2) 。

这样其实就是相当于将原图改造了一下,只要 x 能到达 y ,就直接连一条边 (x, y),这样就可以“绕过”原图的一些被其他路径占用的点,直接构造新路径了。

这样就将可以相交的最小路径覆盖转化为了路径不能相交的最小路径覆盖了。

代码

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

const int MaxN = 100 + 5;

int n, m, Ans, Index;
int Used[MaxN * 2], Father[MaxN * 2];

bool OK[MaxN][MaxN];

struct Edge
{
	int v;
	Edge *Next;
} E[MaxN * MaxN], *P = E, *Point[MaxN];

inline void AddEdge(int x, int y)
{
	++P; P -> v = y;
	P -> Next = Point[x]; Point[x] = P;
}

bool Find(int x)
{
	for (Edge *j = Point[x]; j; j = j -> Next)
	{
		if (Used[j -> v] == Index) continue;
		Used[j -> v] = Index;
		if (Father[j -> v] == 0 || Find(Father[j -> v]))
		{
			Father[j -> v] = x;
			return true;
		}
	}
	return false;
}

int main()
{
	scanf("%d%d", &n, &m);
	int a, b;
	for (int i = 1; i <= m; ++i)
	{
		scanf("%d%d", &a, &b);
		OK[a][b] = true;
	}
	for (int k = 1; k <= n; ++k)
		for (int i = 1; i <= n; ++i)
			for (int j = 1; j <= n; ++j)
				OK[i][j] = OK[i][j] || (OK[i][k] && OK[k][j]);
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			if (OK[i][j]) AddEdge(i, n + j);
	Index = 0;
	Ans = 0;
	for (int i = 1; i <= n; ++i)
	{
		++Index;
		if (Find(i)) ++Ans;
	}
	Ans = n - Ans;
	printf("%d\n", Ans);
	return 0;
}

  

时间: 2024-09-30 14:15:50

[BZOJ 1143] [CTSC2008] 祭祀river 【最长反链】的相关文章

BZOJ 1143: [CTSC2008]祭祀river 最长反链

1143: [CTSC2008]祭祀river Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1143 Description 在遥远的东方,有一个神秘的民族,自称Y族.他们世代居住在水面上,奉龙王为神.每逢重大庆典, Y族都会在水面上举办盛大的祭祀活动.我们可以把Y族居住地水系看成一个由岔口和河道组成的网络.每条河道连接着两个岔口,并且水在河道内按照一个固定

BZOJ 1143 1143: [CTSC2008]祭祀river 最长反链

1143: [CTSC2008]祭祀river Description 在遥远的东方,有一个神秘的民族,自称Y族.他们世代居住在水面上,奉龙王为神.每逢重大庆典, Y族都会在水面上举办盛大的祭祀活动.我们可以把Y族居住地水系看成一个由岔口和河道组成的网络.每条河道连接着两个岔口,并且水在河道内按照一个固定的方向流动.显然,水系中不会有环流(下图描述一个环流的例子). 由于人数众多的原因,Y族的祭祀活动会在多个岔口上同时举行.出于对龙王的尊重,这些祭祀地点的选择必须非常慎重.准确地说,Y族人认为,

Bzoj 2718: [Violet 4]毕业旅行 &amp;&amp; Bzoj 1143: [CTSC2008]祭祀river 传递闭包,二分图匹配,匈牙利,bitset

1143: [CTSC2008]祭祀river Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1878  Solved: 937[Submit][Status][Discuss] Description 在遥远的东方,有一个神秘的民族,自称Y族.他们世代居住在水面上,奉龙王为神.每逢重大庆典, Y族都会在水面上举办盛大的祭祀活动.我们可以把Y族居住地水系看成一个由岔口和河道组成的网络.每条河道连接着两个岔口,并且水在河道内按照一个固定的方向流动.

bzoj 1143: [CTSC2008]祭祀river

Description 在遥远的东方,有一个神秘的民族,自称Y族.他们世代居住在水面上,奉龙王为神.每逢重大庆典, Y族都 会在水面上举办盛大的祭祀活动.我们可以把Y族居住地水系看成一个由岔口和河道组成的网络.每条河道连接着 两个岔口,并且水在河道内按照一个固定的方向流动.显然,水系中不会有环流(下图描述一个环流的例子). 由于人数众多的原因,Y族的祭祀活动会在多个岔口上同时举行.出于对龙王的尊重,这些祭祀地点的选择必 须非常慎重.准确地说,Y族人认为,如果水流可以从一个祭祀点流到另外一个祭祀点

BZOJ 1143: [CTSC2008]祭祀river 最大独立集

题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=1143 题解: 给你一个DAG,求最大的顶点集,使得任意两个顶点之间不可达. 把每个顶点v拆成v和v',对于边u,v,建成(u,v'),得到一个二分图. 先对二分图floyd求闭包,然后求二分图的最大独立集就可以了. 代码: #include<iostream> #include<cstdio> #include<cstring> using namespace

BZOJ 1143 CTSC2008 祭祀river 二分图最大匹配

题目大意:给定一个拓扑图,求一个最大的点集,点集中的点两两不可达 这实际上就是让你求传递闭包后图的最大点独立集- - 利用二分图最大匹配就能搞- - #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 110 using namespace std; int n,m,ans; bool map[M][M]; int state[M],r

1143: [CTSC2008]祭祀river(最长反链)

1143: [CTSC2008]祭祀river 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1143 Description: 在遥远的东方,有一个神秘的民族,自称Y族.他们世代居住在水面上,奉龙王为神.每逢重大庆典, Y族都会在水面上举办盛大的祭祀活动.我们可以把Y族居住地水系看成一个由岔口和河道组成的网络.每条河道连接着两个岔口,并且水在河道内按照一个固定的方向流动.显然,水系中不会有环流(下图描述一个环流的例子). 由于人数众

【BZOJ】1143: [CTSC2008]祭祀river

[题意]求DAG上最多的点使得互不可达. [算法]floyd+最大匹配 [题解] 链是DAG上的一个点集,集合内的点相互单向可达. 反链是DAG上的一个点集,集合内的点相互不可达. 题目显然是求最长反链,转化为最小链覆盖. 最小链覆盖只要求可达,最小路径覆盖却要求相连. 所以floyd传递闭包(用floyd解决01可达信息称为传递闭包),然后最小路径覆盖ans=n-最大匹配. 二分图记得开双倍点. #include<cstdio> #include<algorithm> #incl

[图论训练]1143: [CTSC2008]祭祀river 二分图匹配

Description 在遥远的东方,有一个神秘的民族,自称Y族.他们世代居住在 水面上,奉龙王为神.每逢重大庆典, Y族都会在水面上举办盛大的祭祀活动.我们可以把Y族居住地水系看成一个由岔口和河道组成的网络.每条河道连接着两个岔口,并且水在河道内按照一个固定的 方向流动.显然,水系中不会有环流(下图描述一个环流的例子). 由于人数众多的原因,Y族的祭祀活动会在多个岔口上同时举行.出于对龙王的尊重,这些祭祀地点的选择必须非常慎重.准确地说,Y族人认为,如果水流 可以从一个祭祀点流到另外一个祭祀点