Railway HDU - 3394 (点双连通)

Railway

HDU - 3394

题意:一个无向图,1求不在任何一个环里的边数;2求在不止一个环里的边数。

第一问明显就是求桥,第二问,如果求出的某个点双连通分量里面边数多于点数,说明不止一个环,那么所有的边都在不止一个环里。

该求点双连通的,,求成了边双连通。。。要仔细分析问题。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <vector>
 5 using namespace std;
 6 const int maxv=10010;
 7 int n,m;
 8 int ans1,ans2;
 9 struct Edge{
10     int u,v,nex;
11     bool iscut;
12 }e[100010<<1];
13 int head[maxv];
14 int cnt;
15 void init(){
16     memset(head,-1,sizeof(head));
17     cnt=0;
18 }
19 void add(int u,int v){
20     e[cnt].u=u;
21     e[cnt].iscut=0;
22     e[cnt].v=v;
23     e[cnt].nex=head[u];
24     head[u]=cnt++;
25 }
26 int pre[maxv],bccno[maxv],dfsk,bcc_cnt;
27 int vis[maxv];
28 vector<int> bcc[maxv];
29
30 int dfs(int u,int id){
31     int lowu=pre[u]=++dfsk;
32     for(int i=head[u];i!=-1;i=e[i].nex){
33         int v=e[i].v;
34         if(i==(id^1)) continue;
35         if(!pre[v]){
36             int lowv=dfs(v,i);
37             lowu=min(lowu,lowv);
38             if(lowv>pre[u]) e[i].iscut=e[i^1].iscut=1,ans1++;
39         }
40         else lowu=min(lowu,pre[v]);
41     }
42     return lowu;
43 }
44 void dfs1(int u){
45     bccno[u]=bcc_cnt;
46     vis[u]=1;
47     for(int i=head[u];i!=-1;i=e[i].nex){
48         if(e[i].iscut) continue;
49         bcc[bcc_cnt].push_back(i);
50         int v=e[i].v;
51         if(!vis[v]) dfs1(v);
52     }
53 }
54
55 void find_bcc(int n){
56     memset(pre,0,sizeof(pre));
57     memset(vis,0,sizeof(vis));
58     memset(bccno,0,sizeof(bccno));
59     dfsk=bcc_cnt=0;
60     for(int i=0;i<n;i++) if(!pre[i]) dfs(i,-1);
61     for(int i=0;i<n;i++) if(!vis[i]){
62         bcc_cnt++;
63         bcc[bcc_cnt].clear();
64         dfs1(i);
65     }
66 }
67 int main(){
68        while(scanf("%d%d",&n,&m)&&(n||m)){
69            init();
70            ans1=ans2=0;
71            int u,v;
72            for(int i=0;i<m;i++){
73                scanf("%d%d",&u,&v);
74                add(u,v);
75                add(v,u);
76            }
77            find_bcc(n);
78
79            for(int i=1;i<=bcc_cnt;i++){
80                 int temp=0;
81                 memset(vis,0,sizeof(vis));
82              //   cout<<bcc[i].size()<<endl;
83                 for(int j=0;j<bcc[i].size();j++){
84                  //   printf("---%d---\n",bcc[i][j]);
85                     Edge p=e[bcc[i][j]];
86                     if(!vis[p.u]) {vis[p.u]=1;temp++;}
87                     if(!vis[p.v]) {vis[p.v]=1;temp++;}
88                 }
89                 if(temp<bcc[i].size()/2) ans2+=bcc[i].size()/2;
90            }
91            printf("%d %d\n",ans1,ans2);
92        }
93 }

边双连通=_=

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <vector>
  5 #include <stack>
  6 using namespace std;
  7 const int maxv=10010;
  8 int n,m;
  9 int ans1,ans2;
 10 struct Edge
 11 {
 12     int u,v,nex;
 13 }e[100010<<1];
 14 int head[maxv];
 15 int cnt;
 16 void init()
 17 {
 18     memset(head,-1,sizeof(head));
 19     cnt=0;
 20 }
 21 void add(int u,int v)
 22 {
 23     e[cnt].u=u;
 24     e[cnt].v=v;
 25     e[cnt].nex=head[u];
 26     head[u]=cnt++;
 27 }
 28 int pre[maxv],bccno[maxv],dfsk,bcc_cnt;
 29 stack <int> s;  //存的是边的标号
 30 vector<int> bcc[maxv];  //存的是边的标号
 31 int vis[maxv];
 32
 33 int dfs(int u,int id){
 34     int lowu=pre[u]=++dfsk;
 35     for(int i=head[u];i!=-1;i=e[i].nex){
 36         int v=e[i].v;
 37         if(i==(id^1)) continue;
 38         if(!pre[v]){
 39             s.push(i);
 40             int lowv=dfs(v,i);
 41             lowu=min(lowu,lowv);
 42             if(lowv>pre[u]) ans1++;  //割边
 43             if(lowv>=pre[u]){
 44                 bcc_cnt++;
 45                 bcc[bcc_cnt].clear();
 46                 for(;;){
 47                     int p=s.top();
 48                     s.pop();
 49                     bcc[bcc_cnt].push_back(p);
 50                     if(p==i) break;
 51                 }
 52             }
 53         }
 54         else if(pre[v]<pre[u]){
 55             s.push(i);
 56             lowu=min(lowu,pre[v]);
 57         }
 58     }
 59     return lowu;
 60 }
 61
 62 void find_bcc(int n){
 63     memset(pre,0,sizeof(pre));
 64     memset(bccno,0,sizeof(bccno));
 65     dfsk=bcc_cnt=0;
 66     for(int i=0;i<n;i++) if(!pre[i]) dfs(i,-1);
 67 }
 68
 69 int main(){
 70        while(scanf("%d%d",&n,&m)&&(n||m)){
 71            init();
 72            ans1=ans2=0;
 73            int u,v;
 74            for(int i=0;i<m;i++){
 75                scanf("%d%d",&u,&v);
 76                add(u,v);
 77                add(v,u);
 78            }
 79            find_bcc(n);
 80
 81            for(int i=1;i<=bcc_cnt;i++){
 82                 int temp=0;
 83                 memset(vis,0,sizeof(vis));
 84                 for(int j=0;j<bcc[i].size();j++){
 85                     Edge p=e[bcc[i][j]];
 86                     if(!vis[p.u]) {vis[p.u]=1;temp++;}
 87                     if(!vis[p.v]) {vis[p.v]=1;temp++;}
 88                 }
 89                 if(temp<bcc[i].size()) ans2+=bcc[i].size();
 90            }
 91            printf("%d %d\n",ans1,ans2);
 92         /*
 93         //输出边的顺序看一下挺好的,深入了解前向星工作方式
 94            for(int i=1;i<=bcc_cnt;i++)
 95             {
 96                 for(int j=0;j<bcc[i].size();j++)
 97                     cout<<bcc[i][j]<<" ";
 98                 cout<<endl;
 99             }
100
101         */
102        }
103 }

点双连通

时间: 2024-10-12 03:31:51

Railway HDU - 3394 (点双连通)的相关文章

HDU 4005 The war(双连通好题)

HDU 4005 The war 题目链接 题意:给一个连通的无向图,每条边有一个炸掉的代价,现在要建一条边(你不不知道的),然后你要求一个你需要的最少代价,保证不管他建在哪,你都能炸掉使得图不连通 思路:炸肯定要炸桥,所以先双连通缩点,得到一棵树,树边是要炸的,那么找一个最小值的边,从该边的两点出发,走的路径中,把两条包含最小值的路径,的两点连边,形成一个环,这个环就保证了最低代价在里面,除了这个环以外的最小边,就是答案,这样的话,就利用一个dfs,搜到每个子树的时候进行一个维护即可 代码:

hdu 4612 Warm up 双连通缩点+树的直径

首先双连通缩点建立新图(顺带求原图的总的桥数,其实由于原图是一个强连通图,所以桥就等于缩点后的边) 此时得到的图类似树结构,对于新图求一次直径,也就是最长链. 我们新建的边就一定是连接这条最长链的首尾,这样就将原图的桥减少了直径个. #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<algorithm> #include<map&g

HDU 2460 Network(双连通+树链剖分+线段树)

HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链剖分+线段树处理 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; #pragma comment(linke

HDU 3849 By Recognizing These Guys, We Find Social Networks Useful(双连通)

HDU 3849 By Recognizing These Guys, We Find Social Networks Useful 题目链接 题意:说白了就是求一个无向图的桥 思路:字符串hash掉,然后双连通.要注意特判一下假设不是一个连通块.那么答案是0 代码: #include <cstdio> #include <cstring> #include <string> #include <vector> #include <map> us

HDU 5409 CRB and Graph 双连通缩点 + st表

HDU 5409 显然要先双连通缩成一棵树. 然后对于树上的边才有答案. 对于一条边来说, 两侧的最大值分为mx1 , mx2 , 那么 u 一定是min(mx1, mx2), v 一定是 u + 1. 这个经过仔细分析一下就能得到, 然后按dfs序建个st表就好啦. #include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi firs

HDU - 3394 Railway(连通分量+环)

题目大意:有一个人奇怪的人想要铺路,这个人想把每个环都铺上石头,但是铺石头时不能重复铺,如果重复铺的话,这条边就算损坏 问这个人要损坏多少条边,有多少条边可以不用铺石头 解题思路:不用铺石头的边肯定是桥,因为桥不属于任意一个环 接着判断一下有多少条边会冲突,首先,一个环的话肯定是点-双连通,但点-双连通不一定是个环,所以这个要判断一下. 一个正常的环是要满足 边数=点数 的,如果边数比点数多了,证明这个环被分割成至少三个环了(一个最外围的环,两个被分的小环),可以看出,这三个环每条边都冲突 所以

【图论】双连通总结

双连通总结 这类问题分为,边-双连通,点-双连通 边双连通 边双连通,求出来后,连接没一个双连通的分量的就是割边,因此可以缩点成一棵树,把问题转化为在树上搞,割边的定义为:去掉这条边后图将不连通 基本这类题都一个解法,求双连通分量,然后缩点成树,进行操作 或者就是直接要求割边,做跟割边相关的操作 模板: #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #

双连通

poj 3352 Road Construction && poj 3177 Redundant Paths 给一个无向图,问最少需要添加多少条边,使它成为双连通图. 做法:边双连通缩点,成为一棵树.若要使得任意一棵树,变成一个双连通图,那么至少增加的边数 =(度数为1的结点数 + 1 )/ 2 1 #include<iostream> 2 #include<cstring> 3 #include<string> 4 #include<cstdio

图的连通性问题的小结 (双连通、2-SAT)

图的连通性问题包括: 1.强连通分量. 2.最小点基和最小权点基. 3.双连通. 4.全局最小割. 5.2-SAT 一.强连通分量 强连通分量很少单独出题,一般都是把求强连通分量作为缩点工具. 有三种算法: 1.Kosaraju算法.对原图和反图分别进行一次深度优先搜索. 2.Tarjan算法.用了时间戳. 3.Garbow算法.与Tarjan算法是同一思想,但更精妙. 三种算法的模版我已经贴过了  http://www.cnblogs.com/Potato-lover/p/3956604.ht