zoukankan      html  css  js  c++  java
  • Codeforces Round #397 by Kaspersky Lab and Barcelona Bootcamp (Div. 1 + Div. 2 combined) E. Tree Folding 拓扑排序

    E. Tree Folding

    题目连接:

    http://codeforces.com/contest/765/problem/E

    Description

    Vanya wants to minimize a tree. He can perform the following operation multiple times: choose a vertex v, and two disjoint (except for v) paths of equal length a0 = v, a1, ..., ak, and b0 = v, b1, ..., bk. Additionally, vertices a1, ..., ak, b1, ..., bk must not have any neighbours in the tree other than adjacent vertices of corresponding paths. After that, one of the paths may be merged into the other, that is, the vertices b1, ..., bk can be effectively erased:

    Help Vanya determine if it possible to make the tree into a path via a sequence of described operations, and if the answer is positive, also determine the shortest length of such path.

    Input

    The first line of input contains the number of vertices n (2 ≤ n ≤ 2·105).

    Next n - 1 lines describe edges of the tree. Each of these lines contains two space-separated integers u and v (1 ≤ u, v ≤ n, u ≠ v) — indices of endpoints of the corresponding edge. It is guaranteed that the given graph is a tree.

    Output

    If it is impossible to obtain a path, print -1. Otherwise, print the minimum number of edges in a possible path.

    Sample Input

    6
    1 2
    2 3
    2 4
    4 5
    1 6

    Sample Output

    3

    Hint

    题意

    给你一棵树,可以在这棵树上进行若干次操作,每次操作可以把两条相同的链,根据一个中点合并在一起,具体看题目的图片(CF上面)

    然后问你经过若干次合并之后,最后的最短链长度是多少。

    如果不能合并成一条链,输出-1.

    题解:

    拓扑排序,每次我们从度数为1的点出发bfs。

    然后往上合并,如果遇到交叉点,我们就合并链。

    我们用一个set来合并就好了,如果两条链长度一样,在set里面自动就合并了。

    显然能够bfs的点的set里面只有一个数。

    而且只能有一个点的set里面有两个数。

    最后扫一遍check一下就好了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 2e5+7;
    vector<int> E[maxn];
    int n,vis[maxn],len[maxn],de[maxn],d[maxn];
    set<int> S[maxn];
    int main(){
        scanf("%d",&n);
        for(int i=1;i<n;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            E[a].push_back(b);
            E[b].push_back(a);
            d[a]++;
            d[b]++;
        }
        queue<int> Q;
        for(int i=1;i<=n;i++){
            if(E[i].size()==1){
                Q.push(i);
                S[i].insert(0);
            }
        }
        while(!Q.empty()){
            int now = Q.front();
            vis[now]=1;
            Q.pop();
            for(int i=0;i<E[now].size();i++){
                int v = E[now][i];
                if(vis[v])continue;
                S[v].insert((*S[now].begin())+1);
                d[v]--;
                if(d[v]==1&&S[v].size()==1){
                    Q.push(v);
                }
            }
        }
        int ans = 0,num2 = 0;
        for(int i=1;i<=n;i++){
            if(S[i].size()==0){
                cout<<"-1"<<endl;
                return 0;
            }
            if(S[i].size()>2){
                cout<<"-1"<<endl;
                return 0;
            }
            if(S[i].size()==1){
                ans=max(ans,*S[i].begin());
            }
            if(S[i].size()==2){
                ans=max(ans,*S[i].begin()+*S[i].rbegin());
                num2++;
            }
        }
        if(num2>1){
            cout<<"-1"<<endl;
            return 0;
        }
        while(ans%2==0){
            ans/=2;
        }
        cout<<ans<<endl;
    }
  • 相关阅读:
    libevent中的基本数据结构---queue.h
    TCP 连接关闭及TIME_WAIT探究
    网络程序中常用的三种心跳机制----服务器端
    TCP程序中发送和接收数据
    如何编写一个稳定的网络程序(TCP)
    Linux 编程--三种常用的定时器
    Libevent 事件循环(2)---事件被加入激活队列
    单机千万并发连接实战(修订版)
    千万并发连接实战
    kqueue例子
  • 原文地址:https://www.cnblogs.com/qscqesze/p/6401615.html
Copyright © 2011-2022 走看看