zoukankan      html  css  js  c++  java
  • 牛客小白月赛12 392I

    链接:https://ac.nowcoder.com/acm/contest/392/I
    来源:牛客网

    时间限制:C/C++ 1秒,其他语言2秒
    空间限制:C/C++ 32768K,其他语言65536K
    64bit IO Format: %lld

    题目描述

    月月和华华一起去逛公园了。公园很大,为了方便,可以抽象的看成一个N个点M条边的无向连通图(点是景点,边是道路)。公园唯一的入口在1号点,月月和华华要从这里出发,并打算参观所有的景点。因为他们感情很好,走多远都不会觉得无聊,所以所有景点和道路都可以无数次的重复经过。月月发现,有些路可走可不走,有些路则必须要走,否则就无法参观所有的景点。现在月月想知道,有几条路是不一定要经过的。因为这是个很正常的公园,所以没有重边和自环。

    输入描述:

    第一行两个正整数N和M,表示点数和边数。
    接下来M行,每行两个正整数U和V表示一条无向边。
    保证给定的图是连通的。

    输出描述:

    输出一行一个非负整数表示不一定要经过的边有几条。
    示例1

    输入

    复制
    5 5
    1 2
    2 3
    3 4
    4 5
    3 5

    输出

    复制
    3

    说明

    例如第三条边,月月和华华可以依次走过第一条、第二条、第五条、第四条边走过全部的景点,所以第三条边不一定要经过。同理还有第四条、第五条边,答案为3。

    备注:

    1N1051≤N≤105,1M3×105


    分析 : 求割边(桥)的模板题,注意因为是无向图,所以存边会加倍,应该开2*M大小的边的数组。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <string>
    #include <queue>
    #include <list>
    #include <map>
    #include <set>
    #include <cmath>
    #include <bitset>
    #include <vector>
    #include <iomanip>
    #include <sstream>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    typedef long long  ll;
    #define mem(A, X) memset(A, X, sizeof A)
    #define foreach(e,x) for(__typeof(x.begin()) e=x.begin();e!=x.end();++e)
    #define fori(i,l,u) for(ll (i)=(ll)(l);(i)<=(ll)(u);++(i))
    #define ford(i,l,u) for(ll (i)=(ll)(l);(i)>=(ll)(u);--(i))
    
    
    //--------------------------s
    const int MAXN = 100010;
    const int MAXM = 600010;
    
    vector<int> bridges;
    vector<int> cuts;
    
    
    int head[MAXN], tot;
    struct Edge {
    int u,v, next;
    bool bridge;
    Edge(){}
    Edge(int pu,int pv,int pnext,bool p_bridge){u=pu; v=pv; next=pnext; bridge=p_bridge;}
    } edge[MAXM];
    
    int Low[MAXN], DFN[MAXN];
    bool is_cut[MAXN];
    void init(){
    tot=0;  bridges.clear(); cuts.clear();
    memset(is_cut,false,sizeof(is_cut));
    memset(head,-1,sizeof(head));
    memset(DFN,0,sizeof(DFN));
    }
    void addedge(int u, int v) { // 只添加有向边u->v,无向图双向。 节点标号从0从1开始都可以
    Edge &t=edge[tot]; t=Edge(u,v,head[u],false);
    head[u] = tot++;
    }
    
    void cut_bridge(int u, int father,int dep) { //节点可以标号任意,调用时从任一点调用即可 (1,-1,1)
    Low[u] = DFN[u] = dep;
    int son = 0;
    for (int i = head[u]; i != -1; i = edge[i].next) {
     int v = edge[i].v;
     if (v == father) continue;
     if (!DFN[v]) {
       son++;
       cut_bridge(v, u, dep+1);
       Low[u] = min(Low[u],Low[v]);
       if (Low[v] > DFN[u]) {
           //cout<<"bridges: "<<i<<" "<< (i^1) <<endl;
           edge[i].bridge=true; edge[i^1].bridge=true; } //桥 此处为无向图,故双向。
       if (-1 != father && Low[v] >= DFN[u])  is_cut[u]=true; //割点 不是树根时
     } else  {
       Low[u] =min(Low[u], DFN[v]);
     }
    }
    if (-1 == father && son > 1) is_cut[u]=true;//割点 是树根时
    }
    //---------------------------------------------------e
    //bug记录:
    //多组输入时每次 init().
    int n,m;
    
    int main()
    {
      ios::sync_with_stdio(false);
      //freopen("local.in","r",stdin);
      while(cin>>n>>m){
        //cout<<"n,m"<<n<<" "<<m<<endl;
        init();
        fori(i,0,m-1){
            int u,v;
            cin>>u>>v;
            addedge(u,v);
            addedge(v,u);
        }
        cut_bridge(1,-1,1);
        int cnt=0;
        fori(i,0,tot-1){
            if(edge[i].bridge) cnt++;
        }
        //cout<<"cnt: "<<cnt<<endl;
        cout<<m-cnt/2<<endl;
      }
    
    
    return 0;
    }
    View Code
  • 相关阅读:
    document.getElementById的简便方式
    uri编解码
    javascript数组
    前端网站收藏
    html5 canvas
    interview material
    Merge into(oracle)
    机器学习入门二 ----- 机器学习术语表
    机器学习入门一 ------- 什么是机器学习,机器学习的在实际中的用处
    Dubbo 源码分析系列之一环境搭建
  • 原文地址:https://www.cnblogs.com/paulzjt/p/10544377.html
Copyright © 2011-2022 走看看