• USACO 2018 December Contest Platinum T3: The Cow Gathering


    题目大意

    奶牛们从世界各地聚集起来参加一场大型聚会。总共有 N 头奶牛, N1 对奶牛互为朋友。每头奶牛都可以通过一些朋友关系认识其他每头奶牛。

    她们玩得很开心,但是现在到了她们应当离开的时间了,她们会一个接一个地离开。她们想要以某种顺序离开,使得只要至少还有两头奶牛尚未离开,所有尚未离开的奶牛都还有没有离开的朋友。此外,由于行李寄存的因素,有 M 对奶牛 (ai,bi) 必须满足奶牛 ai 要比奶牛 bi 先离开。注意奶牛 ai 和奶牛 bi 可能是朋友,也可能不是朋友。

    帮助奶牛们求出,对于每一头奶牛,她是否可以成为最后一头离开的奶牛。可能会发生不存在满足上述要求的奶牛离开顺序的情况。

    题目分析

    从“总共有 N 头奶牛, N1 对奶牛互为朋友”可知,合法情况下(有答案),这N头奶牛的关系构成了一棵树。若是构成环或其他形态,则该题答案均为0。

    以下分析建立在 “这N头奶牛的关系构成了一棵树” 这样的合法情况下。

    若没有行李寄存的限制,明显,每头牛都可以成为最后离开的牛。

    而若有一对限制(a, b),a 要比奶牛 b 先离开,那么这样的话,以b为根的情况下,a的子树中的点 因为要比a先离开,所以他们比不会成为剩下两个点中的一个,

    也就是说,他们的答案都为0。

    我们将所有的a打上标记。

    观察到,若 点x 为一可行点(答案为1),则把 x 点提为根,从根往下dfs,碰到有标记的点立即返回,那么它能到达的所有点都为可行点。

    所以我们只需通过一遍拓扑排序找到一个可行点后dfs即可。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int MAXN=1e5+10;
     4 
     5 struct Edge{
     6     int to,nxt;
     7 }e[MAXN<<1];
     8 int cnt,head[MAXN];
     9 inline void add_edge(int u,int v){
    10     e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
    11 }
    12 int n,m,rt;
    13 int ind[MAXN];
    14 bool vis[MAXN],f[MAXN];
    15 vector<int> lim[MAXN];
    16 queue<int> q;
    17 inline int Solve(){
    18     int tot=0;
    19     while(!q.empty()){
    20         int x=q.front();q.pop();
    21         ++tot;
    22         if(ind[x]!=1){
    23             if(!ind[x]) return x;
    24             //for(int i=1;i<=n;++i)
    25             //    printf("0
    ");
    26             //exit(0);
    27         }
    28         for(int i=head[x],y;i;i=e[i].nxt){
    29             y=e[i].to;
    30             --ind[y];++tot;
    31             if(ind[y]==1) q.push(y);
    32         }
    33         for(int i=0,y;i<(int)lim[x].size();++i){
    34             y=lim[x][i];
    35             --ind[y];++tot;
    36             if(ind[y]==1) q.push(y);
    37         }
    38     }
    39     if(tot!=n){
    40         for(int i=1;i<=n;++i)
    41                 printf("0
    ");
    42             exit(0);
    43     }
    44 }
    45 inline void dfs(int x,int fa=0){
    46     f[x]=1;
    47     for(int i=head[x],y;i;i=e[i].nxt){
    48         y=e[i].to;
    49         if(y!=fa&&!vis[y])
    50             dfs(y,x);
    51     }
    52 }
    53 int main(){
    54     scanf("%d%d",&n,&m);
    55     for(int i=1,u,v;i<n;++i){
    56         scanf("%d%d",&u,&v);
    57         add_edge(u,v);
    58         add_edge(v,u);
    59         ++ind[u];++ind[v];
    60     }
    61     for(int i=1,u,v;i<=m;++i){
    62         scanf("%d%d",&u,&v);
    63         lim[u].push_back(v);
    64         ++ind[v];
    65         vis[u]=true;
    66     }
    67     for(int i=1;i<=n;++i)
    68         if(ind[i]==1)
    69             q.push(i);
    70     rt=Solve();
    71     dfs(rt);
    72     for(int i=1;i<=n;++i)
    73         printf("%d
    ",f[i]?1:0);
    74     return 0;
    75 }
  • 相关阅读:
    Java设计模式--命令模式
    linux 挂载windows盘
    C# 对含有向量偏移的明文进行AES加解密
    Vue修仙之旅之Vue初尝
    Cookie的Secure属性
    Webserver信息泄露的解决方案--使用StripHeaders模块删除不必要的header
    window自定义事件
    vue typescript .eslintrc.js
    css word-break: break-word;无效
    vscode vue 片段
  • 原文地址:https://www.cnblogs.com/LI-dox/p/11217748.html
Copyright © 2020-2023  润新知