zoukankan      html  css  js  c++  java
  • HDU 3749 Financial Crisis 经济危机(点双连通分量)

    题意:

      给一个图n个点m条边(不一定连通),接下来又q个询问,询问两个点是为“不相连”,“仅有一条路径可达”,“有两条及以上的不同路径可达”三种情况中的哪一种。注:两条以上的路径指的是路径上的点连1个点也不重复。

    思路:并查集+tarjan求割点。

      (1)情况一:先并查集处理,如果两个点从一开始就不连通,直接输出zero

      (2)情况二和情况三:两点既然连通,那么可能是只有1条路径,比如中间隔着一个割点;也可能有多条路径,比如在同一个双连通分量内。那么直接判断其是否在同一个双连通分量内即可,若在同一个双连通分量内,那么路径起码有2条不重复的。

      并查集算法看其他题目。

      tarjan用刘汝佳那个版本。只是我用了unordered_set来存储双连通分量,对于每个询问就在每个双连通分量中查是否同时存在(因为其中一个可能是割点),若同时存在且size>2才是输出 two or more。

      具体实现看代码。

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 const int N=5000+5;
      4 stack< pair<int,int> >  stac;   //tarjan用的栈
      5 vector<int> vect[N];            //
      6 unordered_set<int>  bi[N];      //双连通分量
      7 
      8 int pre[N];            //并查集用的,保存领导
      9 
     10 int find(int x)        //
     11 {
     12     return pre[x]==x? x: pre[x]=find(pre[x]);
     13 }
     14 
     15 void joint(int x,int y)  //
     16 {
     17     x=find(x);
     18     y=find(y);
     19     if(x!=y)    pre[x]=y;
     20 }
     21 
     22 
     23 int dfn[N], low[N];
     24 int bccno[N];
     25 int cnter, bcc_cnt;
     26 
     27 void DFS(int x, int far)
     28 {
     29     dfn[x]= low[x]= ++cnter;
     30     int chd=0;  //孩子
     31     for(int i=0; i<vect[x].size(); i++)
     32     {
     33         int t=vect[x][i];
     34 
     35         if(!dfn[t]) //树边
     36         {
     37             chd++;
     38             stac.push(make_pair(x,t));      //进栈
     39             DFS(t,x);
     40             low[x]=min(low[x],low[t]);
     41             //if((far&&low[t]>=dfn[x]) || (!far&&chd>1) )      //割点
     42             if(low[t]>=dfn[x] )      //割点。如果根只有0或1个孩子呢?那根就不是连通分量中的一个点。
     43             {
     44                 bi[++bcc_cnt].clear(); //连通分量
     45                 while(1)
     46                 {
     47                     int a=stac.top().first;
     48                     int b=stac.top().second;
     49                     stac.pop();
     50                     if(bccno[a]!=bcc_cnt)
     51                     {
     52                         bccno[a]=bcc_cnt;
     53                         bi[bcc_cnt].insert(a);
     54                     }
     55                     if(bccno[b]!=bcc_cnt)
     56                     {
     57                         bccno[b]=bcc_cnt;
     58                         bi[bcc_cnt].insert(b);
     59                     }
     60                     if(a==x && b==t)  break;
     61                 }
     62             }
     63         }
     64         else if(dfn[t]<dfn[x] && t!=far)
     65         {
     66             stac.push(make_pair(x,t));      //进栈
     67             low[x]=min(low[x],dfn[t]);
     68         }
     69     }
     70 }
     71 
     72 int cal_bcc(int n)
     73 {
     74     memset(bccno,0,sizeof(bccno));
     75     memset(dfn,0,sizeof(dfn));
     76     memset(low,0,sizeof(low));
     77 
     78     while(!stac.empty())    stac.pop();
     79 
     80     bcc_cnt= cnter=0;
     81     for(int i=n; i>0; i--)
     82         if(!dfn[i])    DFS(i,0);
     83 }
     84 
     85 
     86 int check(int n,int a, int b)
     87 {
     88     if(find(a)!=find(b))    return 0;   //不连通
     89 
     90     for(int i=1; i<=bcc_cnt; i++)
     91     {
     92         if(bi[i].find(a)!=bi[i].end() && bi[i].find(b)!=bi[i].end() && bi[i].size()>2)  //对于只有两个点的双连通分量,仅有1条边,输出one。
     93         {
     94             printf("two or more
    ");
     95             return 1;
     96         }
     97     }
     98     printf("one
    ");
     99     return 1;
    100 }
    101 
    102 void init(int n)
    103 {
    104     memset(pre,0,sizeof(pre));
    105     for(int i=1; i<=n; i++) vect[i].clear();
    106     for(int i=1; i<=n; i++) pre[i]=i;
    107 }
    108 
    109 int main()
    110 {
    111     freopen("input.txt", "r", stdin);
    112     int n, m, q, a, b, j=0;
    113     while(scanf("%d%d%d",&n, &m, &q), n+m+q)
    114     {
    115         init(n);
    116         for(int i=0; i<m; i++)
    117         {
    118             scanf("%d%d", &a, &b);
    119             vect[++a].push_back(++b);
    120             vect[b].push_back(a);
    121             joint(a,b);             //并查集
    122         }
    123 
    124         cal_bcc(n);                 //tarjan算法
    125         printf("Case %d:
    ",++j);
    126 /*
    127         for(int i=1; i<=bcc_cnt; i++)     //输出每个双连通分量。
    128         {
    129             printf("第%d个双连通分量包含以下点:",i);
    130             for(unordered_set<int>::iterator it=bi[i].begin(); it!=bi[i].end();it++)
    131             {
    132                 printf("%d ",*it);
    133             }
    134             printf("
    ");
    135         }
    136 */
    137         for(int i=0; i<q; i++)
    138         {
    139             scanf("%d%d", &a, &b);
    140             if(!check(n, ++a, ++b)) printf("zero
    ");
    141         }
    142     }
    143     return 0;
    144 }
    AC代码

      

      

  • 相关阅读:
    Java语言基础(3)
    Java语言基础(2)
    Java语言基础(1)
    标准C语言(13)
    标准C语言(12)
    标准C语言(11)
    标准C语言(10)
    IDEA 学习笔记之 Console显示日志大小
    Java 学习笔记之 线程sleep方法
    Java 学习笔记之 线程isAlive方法
  • 原文地址:https://www.cnblogs.com/xcw0754/p/4617176.html
Copyright © 2011-2022 走看看