【NOIP2013模拟】Vani和Cl2捉迷藏

文章目录

题目

Description
vanicl2在一片树林里捉迷藏……
这片树林里有 N N N座房子, M M M条有向道路,组成了一张有向无环图。
树林里的树非常茂密,足以遮挡视线,但是沿着道路望去,却是视野开阔。如果从房子A沿着路走下去能够到达B,那么在AB里的人是能够相互望见的。
现在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 N10 M ≤ 20 M\leq20 M20
对于 60 % 60\% 60%的数据, N ≤ 100 N≤100 N100 M ≤ 1000 M\leq1000 M1000
对于 100 % 100\% 100%的数据, N ≤ 200 N≤200 N200 M ≤ 30000 M\leq30000 M30000 1 ≤ x , y ≤ N 1\leq x,y\leq N 1x,yN

分析

先用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);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值