题目
Description
vani和cl2在一片树林里捉迷藏……
这片树林里有
N
N
N座房子,
M
M
M条有向道路,组成了一张有向无环图。
树林里的树非常茂密,足以遮挡视线,但是沿着道路望去,却是视野开阔。如果从房子A沿着路走下去能够到达B,那么在A和B里的人是能够相互望见的。
现在cl2要在这
N
N
N座房子里选择
K
K
K座作为藏身点,同时vani也专挑cl2作为藏身点的房子进去寻找,为了避免被vani看见,cl2要求这
K
K
K个藏身点的任意两个之间都没有路径相连。
为了让vani更难找到自己,cl2想知道最多能选出多少个藏身点?
Input
第一行两个整数
N
N
N,
M
M
M。
接下来
M
M
M行每行两个整数
x
x
x、
y
y
y,表示一条从
x
x
x到
y
y
y的有向道路。
Output
一个整数K,表示最多能选取的藏身点个数。
Sample Input
4 4
1 2
3 2
3 4
4 2
Sample Output
2
Data Constraint
对于
20
%
20\%
20%的数据,
N
≤
10
N≤10
N≤10,
M
≤
20
M\leq20
M≤20;
对于
60
%
60\%
60%的数据,
N
≤
100
N≤100
N≤100,
M
≤
1000
M\leq1000
M≤1000;
对于
100
%
100\%
100%的数据,
N
≤
200
N≤200
N≤200,
M
≤
30000
M\leq30000
M≤30000,
1
≤
x
,
y
≤
N
1\leq x,y\leq N
1≤x,y≤N。
分析
先用Floyd求出任意两点 u u u是否可以到 v v v(传递闭包)得到图 G ′ G' G′,感性理解我们要求的是 G ′ G' G′中的最小路径覆盖数。于是有这个结论:
DAG的最小路径覆盖数 = DAG结点数 - DAG拆点后对应的二分图的最大匹配数
根据
G
′
G'
G′拆点建图。简单来说就是:如果
u
u
u可到
v
v
v,就将
u
u
u和
v
′
v'
v′连边。
样例如图(样例中
G
=
G
′
G=G'
G=G′):
代码
考场上补题时很急,写得很丑,,,
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 200
int N,M;
bool G[MAXN+5][MAXN+5];
vector<int> GG[2*MAXN+5];
bool vis[2*MAXN+5];
int Match[2*MAXN+5];
bool dfs(int u){
for(int i=0;i<int(GG[u].size());i++){
int v=GG[u][i];
if(!vis[v]){
vis[v]=1;
if(Match[v]==-1||dfs(Match[v])){
Match[u]=v;
Match[v]=u;
return 1;
}
}
}
return 0;
}
int main(){
scanf("%d%d",&N,&M);
for(int i=1;i<=M;i++){
int u,v;
scanf("%d%d",&u,&v);
G[u][v]=1;
}
for(int k=1;k<=N;k++)
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
G[i][j]=G[i][j]||(G[i][k]&&G[k][j]);
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
if(G[i][j]){
GG[i].push_back(j+N);
GG[j+N].push_back(i);
}
memset(Match,-1,sizeof Match);
N*=2;
int Ans=0;
for(int i=1;i<=N;i++)
if(Match[i]==-1){
memset(vis,0,sizeof vis);
Ans+=dfs(i);
}
printf("%d",N/2-Ans);
}