jzoj3423NOIP2013模拟匈牙利Vani和Cl2捉迷藏

Posted SSL_ZZL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jzoj3423NOIP2013模拟匈牙利Vani和Cl2捉迷藏相关的知识,希望对你有一定的参考价值。

题面

Description

vani和cl2在一片树林里捉迷藏……

这片树林里有N座房子,M条有向道路,组成了一张有向无环图。

树林里的树非常茂密,足以遮挡视线,但是沿着道路望去,却是视野开阔。如果从房子A沿着路走下去能够到达B,那么在A和B里的人是能够相互望见的。

现在cl2要在这N座房子里选择K座作为藏身点,同时vani也专挑cl2作为藏身点的房子进去寻找,为了避免被vani看见,cl2要求这K个藏身点的任意两个之间都没有路径相连。

为了让vani更难找到自己,cl2想知道最多能选出多少个藏身点?

Input

第一行两个整数N,M。

接下来M行每行两个整数x、y,表示一条从x到y的有向道路。

Output

一个整数K,表示最多能选取的藏身点个数。

Sample Input

4 4
1 2
3 2
3 4
4 2

Sample Output

2

Data Constraint

对于20% 的数据,N≤10,M<=20。
对于60% 的数据, N≤100,M<=1000。
对于100% 的数据,N≤200,M<=30000,1<=x,y<=N。


解题思路

first,我思路来源完全没看懂
then,我啥证明都没看懂
以下为题解复制
在这里插入图片描述
上方的博客证明


反链和题面要求的东西是完全相同的,就是两个点之间相连是链,无法相连就是反链
以上是求反链的问题转换
现在 (我能) 知道的是,求反链变成了求最小链覆盖

以我考场的 (不成熟) 思路,就是每一条‘单独’的链 (我也不知道是啥) 只能选一个点
样例为例(箭头就不画了,太难了),第三个链是重复的,每条不重复的链选一个,也就是两个
在这里插入图片描述

不重复的链,也就是最小链覆盖
怎么求呢?最小链覆盖 = 总点数n - 最大覆盖

首先需要明确的是,在找边的时候(就是连边),是要跳过重复点的
这个用Floyd把边传递下去
在这里插入图片描述
1-》3-》4,那么2就不能连到3(重复),用Floyd传递成2-》5
在这里插入图片描述
2-》3和3-》5并不用管,因为它们不会影响最大覆盖

最大覆盖
由于我不会网络流,所以我用的匈牙利
匈牙利将链全部画出来,而没有连出的点就是最小链覆盖
(剔除掉的边3->2, 4->2,n-最大覆盖=2)
在这里插入图片描述
(不管怎么剔除都一样,剔除掉边1->2, 3->2,n-最大覆盖=2)
在这里插入图片描述


Code

#include <iostream>
#include <cstring> 
#include <cstdio>

using namespace std;

struct DT{
	int to, next;
}a[5001000];
int n, m, x, y, ans, num;
int f[5100][5100], t[5100], p[5100], head[5100];

void add(int x, int y) {
	a[++num] = (DT){y, head[x]};
	head[x] = num;
}

bool find(int x) {  //匈牙利
	for(int i = head[x]; i; i = a[i].next) {
		int y = a[i].to;
		if(!p[y]) {
			p[y] = 1;
			int now = t[y];
			t[y] = x;
			if(!now || find(now)) return 1;
			t[y] = now;
		}
	}
	return 0;
}

int main() {
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= m; i++) {
		scanf("%d%d", &x, &y);
		add(x, y);
		f[x][y] = 1;
	}
	for(int k = 1; k <= n; k++)
		for(int i = 1; i <= n; i++)
			for(int j = 1; j <= n; j++) {
				if(i == j || j == k || k == i) continue;
				if(f[i][k] && f[k][j]) {  //传递边
					f[i][j] = 1;
					add(i, j);  
				}
			}
	for(int i = 1; i <= n; i++) {
		memset(p, 0, sizeof(p));
		if(find(i))
			ans++;
	}
	printf("%d", n - ans);
} 

以上是关于jzoj3423NOIP2013模拟匈牙利Vani和Cl2捉迷藏的主要内容,如果未能解决你的问题,请参考以下文章

jzoj3510NOIP2013模拟11.5B组DAY 1 (7.12)DP最短路径(path)

jzoj3505NOIP2013模拟11.4A组组合逆元积木

[jzoj]3456.NOIP2013模拟联考3恭介的法则(rule)

jzoj3515NOIP2013模拟11.6B组二分DP软件公司

jzoj3523NOIP2013模拟11.7A组树上倍增JIH的玩偶(tree)

jzoj3528NOIP2013模拟11.7A组数学拓扑DP图书馆(library)