zoukankan      html  css  js  c++  java
  • codeforces 862B Mahmoud and Ehab and the bipartiteness (DFS或带权并查集)

    B. Mahmoud and Ehab and the bipartiteness
    time limit per test
    2 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    Mahmoud and Ehab continue their adventures! As everybody in the evil land knows, Dr. Evil likes bipartite graphs, especially trees.

    A tree is a connected acyclic graph. A bipartite graph is a graph, whose vertices can be partitioned into 2 sets in such a way, that for each edge (u, v) that belongs to the graph, u and v belong to different sets. You can find more formal definitions of a tree and a bipartite graph in the notes section below.

    Dr. Evil gave Mahmoud and Ehab a tree consisting of n nodes and asked them to add edges to it in such a way, that the graph is still bipartite. Besides, after adding these edges the graph should be simple (doesn't contain loops or multiple edges). What is the maximum number of edges they can add?

    A loop is an edge, which connects a node with itself. Graph doesn't contain multiple edges when for each pair of nodes there is no more than one edge between them. A cycle and a loop aren't the same .

    Input

    The first line of input contains an integer n — the number of nodes in the tree (1 ≤ n ≤ 105).

    The next n - 1 lines contain integers u and v (1 ≤ u, v ≤ n, u ≠ v) — the description of the edges of the tree.

    It's guaranteed that the given graph is a tree.

    Output

    Output one integer — the maximum number of edges that Mahmoud and Ehab can add to the tree while fulfilling the conditions.

    Examples
    Input
    3
    1 2
    1 3
    Output
    0
    Input
    5
    1 2
    2 3
    3 4
    4 5
    Output
    2
    Note

    Tree definition: https://en.wikipedia.org/wiki/Tree_(graph_theory)

    Bipartite graph definition: https://en.wikipedia.org/wiki/Bipartite_graph

    In the first test case the only edge that can be added in such a way, that graph won't contain loops or multiple edges is (2, 3), but adding this edge will make the graph non-bipartite so the answer is 0.

    In the second test case Mahmoud and Ehab can add edges (1, 4) and (2, 5).

    分析:要把所有的点分成两个集合,那么最多的情况就是一个集合中所有的点都连接另一个集合中所有的点..

    需要注意的是 此时它是一个树结构也就是说所有的点都直接或间接的存在着关系

    那么当我们从一个点开始DFS的时候,奇数次的时候扫的点属于一个集合,偶数次的点属于另一个集合,这样的话,就能找出最多的边数,减去现在已有的边数就能得到答案

    DFS:

    #include <stdio.h>
    #include <algorithm>
    #include <iostream>
    #include <string.h>
    #include <queue>
    #include <vector>
    using namespace std;
    typedef long long ll;
    vector<int>V[100100];
    int vis[100100];
    ll num0;
    ll num1;
    void dfs(int x,int step)
    {
       for(int i=0;i<V[x].size();i++)
       {
           if(!vis[V[x][i]])
           {
               vis[V[x][i]]=1;
              if(step%2==1)num0++;
              else num1++;
              dfs(V[x][i],step+1);
           }
       }
    }
    int main()
    {
        int  n,a,b;
        scanf("%d",&n);
        for(int k=0;k<n-1;k++){
            num1=0;
            scanf("%d%d",&a,&b);
            V[a].push_back(b);
            V[b].push_back(a);
        }
             num0=1;
            vis[1]=1;
            dfs(1,0);
            cout<<num0*num1-(n-1)<<endl;
        return 0;
    }

     还可以从带权并查集来考虑,用0和1的权值将所有的点分成两个集合,需要注意的是每个点在最后Find操作进行,累加之后才是最后的权值

    #include <stdio.h>
    #include <algorithm>
    #include <iostream>
    #include <string.h>
    #include <queue>
    #include <vector>
    using namespace std;
    typedef long long ll;
    int F[100010];
    int val[100010];
    int Find(int x)
    {
        if(F[x]==-1)return x;
        int tmp=Find(F[x]);
        val[x]+=val[F[x]];
        val[x]%=2;
        return F[x]=tmp;
    }
    int main()
    {
       int n,a,b;
       ll num0,num1;
       scanf("%d",&n);
       memset(F,-1,sizeof(F));
       memset(val,0,sizeof(val));
       num0=0;
       num1=0;
       for(int k=0;k<n-1;k++)
       {
          scanf("%d%d",&a,&b);
          int t1=Find(a);
          int t2=Find(b);
          if(t1!=t2)
          {
            F[t2]=t1;
            val[t2]=(val[a]-val[b]+1+2)%2;
          }
             //  cout<<val[a]<<" "<<val[b]<<endl;
       }
       for(int k=1;k<=n;k++)
       {
        int  t1=Find(k);//这样才能得到该点最后的权值
        if(val[k]==0)
          num0++;
        else
           num1++;
       }
     //  cout<<num0<<" "<<num1<<endl;
       cout<<num0*num1-(n-1)<<endl;
        return 0;
    }

                    

  • 相关阅读:
    关于回调地狱
    node.js 关于跨域和传递给前台参数
    关于js的当前日期的格式化,和两个日期之间的相减的天数
    CSS 关于让页面的高度达到电脑屏幕的底部
    前端 为什么我选择用框架而不是Jquery
    关于webpack打包图片的路径问题
    关于webpack打包js和css
    微信小程序网络请求的setDate
    WinSocket聊天程序实例(多线程)
    Orcal的JDBC数据连接方式
  • 原文地址:https://www.cnblogs.com/a249189046/p/7560208.html
Copyright © 2011-2022 走看看