Vani和Cl2捉迷藏(二分图最小路径可重点覆盖/可相交最小路径覆盖)(2019-中山集训)[NOIP2013模拟]

前言

一两年前见过没打…

题目

一个 D A G DAG DAG,问最多放置多少个点使得两两之间无法到达(单向)?
数据范围 n &lt; = 200 , m &lt; = 30000 n&lt;=200,m&lt;=30000 n<=200,m<=30000

思路

可以看作可相交最小路径覆盖数,为什么呢,因为此时一条路径上必存在一个点使得其他路径均无法到达,否则可以删去这条路径,因为这条路径上的边都被其他路径瓜分了…
然后考虑两点之间到达情况,可由不相交最小路径覆盖=点数-最大匹配拓展,Floyd传递闭包后使得可以相交,匈牙利跑一遍即可

代码

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<climits>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define LL long long
#define ULL unsigned long long
using namespace std;
int read(){
	int f=1,x=0;char c=getchar();
	while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
	while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return f*x;
}
#define MAXN 200
vector<int> G[2*MAXN+5];
inline void Addedge(int u,int v){
	G[u].push_back(v);
	G[v].push_back(u);
	return ;
}
bool f[MAXN+5][MAXN+5];
void Floyd(int n){
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				f[i][j]|=f[i][k]&f[k][j];
	return ;
}
int ma[2*MAXN+5],vis[2*MAXN+5];
bool DFS(int u){
	for(int i=0;i<int(G[u].size());i++){
		int v=G[u][i];
		if(vis[v]) continue;
		vis[v]=1;
		if(!ma[v]||DFS(ma[v])){
			ma[v]=u,ma[u]=v;
			return 1;
		}
	}
	return 0;
}
int main(){
	int n=read(),m=read();
	for(int i=1;i<=m;i++){
		int u=read(),v=read();
		f[u][v]=1;
	}
	Floyd(n);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(f[i][j])
				Addedge(i,n+j);
	int ans=0;
	for(int i=1;i<=n;i++)
		if(!ma[i]){
			memset(vis,0,sizeof(vis));
			ans+=DFS(i);
		}
	printf("%d\n",n-ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值