cut point and bridge

图的割点与桥:

 

dfs树的割点程序代码:

原解释里面是错的。

 1 #include <iostream>
 2 #include <cstdio>
 3 
 4 using namespace std;
 5 
 6 bool adj[10][10];
 7 int visit[10];
 8 int grand[10];
 9 
10 int t=0;
11 
12 void DFS(int p,int i)
13 {
14     visit[i]=++t;
15     grand[i]=i;
16     
17     int child=0;
18     bool ap=false;
19     
20     for(int j=0;j<10;j++)
21         if(adj[i][j] && j!=p)
22         {
23             if(visit[j])
24             {
25                 if(visit[j]<visit[grand[i]])
26                     grand[i]=j;
27             }
28             else
29             {
30                 child++;
31                 DFS(i,j);
32                 
33                 if(visit[grand[i]]>visit[grand[j]])
34                     grand[i]=grand[j];
35                 
36                 if(visit[grand[j]]>=visit[i])
37                     ap=true;
38             }
39         }
40     
41     if((i==p && child>1) || (i!=p && ap))
42         cout<<""<<i<<"点是关节点"<<endl;
43 }
44 
45 void articulation_vertex()
46 {
47     memset(visit,0,sizeof(visit));
48     
49     t=0;
50     
51     for(int i=0;i<10;i++)
52         if(!visit[i])
53             DFS(i,i);
54 }
55 
56 int main()
57 {
58     int a,b;
59     memset(adj,0,sizeof(adj));
60     for(int i=0;i<11;i++)
61     {
62         scanf("%d%d",&a,&b);
63         adj[a][b]=adj[b][a]=1;
64     }
65     articulation_vertex();
66     return 0;
67 }
View Code

 

记录遍历顺序值

 1 #include <iostream>
 2 #include <cstdio>
 3 
 4 using namespace std;
 5 
 6 bool adj[10][10];
 7 int visit[10];
 8 int low[10];
 9 
10 int t=0;
11 
12 void DFS(int p,int i)
13 {
14     visit[i]=low[i]=++t;
15     
16     int child=0;
17     bool ap=false;
18     
19     for(int j=0;j<10;j++)
20         if(adj[i][j] && j!=p)
21         {
22             if(visit[j])
23             {
24                 low[i]=min(low[i],visit[j]);
25             }
26             else
27             {
28                 child++;
29                 DFS(i,j);
30                 
31                 low[i]=min(low[i],low[j]);
32                 
33                 if(low[j]>=visit[i])
34                     ap=true;
35             }
36         }
37     
38     if((i==p && child>1) || (i!=p && ap))
39         cout<<""<<i<<"点是关节点"<<endl;
40 }
41 
42 void articulation_vertex()
43 {
44     memset(visit,0,sizeof(visit));
45     
46     t=0;
47     
48     for(int i=0;i<10;i++)
49         if(!visit[i])
50             DFS(i,i);
51 }
52 
53 int main()
54 {
55     int a,b;
56     memset(adj,0,sizeof(adj));
57     for(int i=0;i<11;i++)
58     {
59         scanf("%d%d",&a,&b);
60         adj[a][b]=adj[b][a]=1;
61     }
62     articulation_vertex();
63     return 0;
64 }
View Code

 

 

 

 1 #include <iostream>
 2 #include <cstdio>
 3 
 4 using namespace std;
 5 
 6 int visit[10];
 7 int low[10];
 8 int adj[10][10];
 9 int parent[10];
10 int t;
11 
12 void DFS(int i)
13 {
14     visit[i]=low[i]=++t;
15     
16     for(int j=0;j<10;j++)
17     {
18         if(adj[i][j])
19         {
20             if(!visit[j])
21         {
22             parent[j]=i;
23             DFS(j);
24             low[i]=min(low[i],low[j]);
25         }
26         else if(parent[i]!=j)
27             low[i]=min(low[i],visit[j]);
28         }
29     }
30 }
31 
32 void articulation_vertex()
33 {
34     memset(visit,0,sizeof(visit));
35     t=0;
36     for(int i=0;i<10;i++)
37     {
38         if(!visit[i])
39         {
40             parent[i]=i;
41             DFS(i);
42         }
43     }
44     
45     for(int i=0;i<10;i++)
46     {
47         if(i==parent[i])
48         {
49             int child=0;
50             for(int j=0;j<10;j++)
51                 if(parent[j]==i && i!=j)
52                     child++;
53             if(child>1)
54                 cout<<"Articulation Vertex:"<<i<<endl;
55         }
56         else
57         {
58             bool ap=false;
59             for(int j=0;j<10;j++)
60                 if(parent[j]==i && low[j]>=visit[i])
61                     ap=true;
62             if(ap)
63                 cout<<"Articulation Vertex:"<<i<<endl;
64             
65         }
66     }
67 }
68 
69 int main()
70 {
71     int a,b;
72     memset(adj,0,sizeof(adj));
73     for(int i=0;i<11;i++)
74     {
75         scanf("%d%d",&a,&b);
76         adj[a][b]=adj[b][a]=1;
77     }
78     articulation_vertex();
79     return 0;
80 }
View Code

 

 1 #include <iostream>
 2 #include <cstdio>
 3 
 4 using namespace std;
 5 
 6 
 7 int adj[10][10];
 8 int visit[10];
 9 int low[10];
10 
11 int t=0;
12 
13 void DFS(int p,int i)
14 {
15     visit[i]=low[i]=++t;
16     
17     for(int j=0;j<10;j++)
18         if(adj[i][j])
19         {
20             if(!visit[j])
21             {
22                 DFS(i,j);
23                 
24                 low[i]=min(low[i],low[j]);
25                 
26                 if(low[j]>visit[i])
27                     cout<<"bridge:"<<i<<"---"<<j<<endl;
28             }
29             else if(j!=p || (j==p && adj[i][j]>=2))
30             {
31                 low[i]=min(low[i],low[j]);
32             }
33         }
34 }
35 
36 void bridge()
37 {
38     memset(visit,0,sizeof(visit));
39     t=0;
40     
41     for(int i=0;i<10;i++)
42         if(!visit[i])
43             DFS(i,i);
44 }
45 
46 int main()
47 {
48     int a,b;
49     memset(adj,0,sizeof(adj));
50     for(int i=0;i<11;i++)
51     {
52         scanf("%d%d",&a,&b);
53         adj[a][b]=adj[b][a]=1;
54     }
55     bridge();
56     return 0;
57     
58 }
bridge

 

程序代码分割为两段后的

 1 1 2
 2 1 0
 3 1 3
 4 3 4
 5 4 0
 6 0 5
 7 5 7
 8 5 6
 9 6 7
10 7 8
11 7 9
View Code

 

 

poj,3694

tarjan求出桥,然后并查集缩点,最后成为一棵树,然后树边即为桥边,然后添边,如果u,v在一个集合中就没关系。

如果u,v在两个集合中就要对这两个集合间的集合缩点,每缩一次点就减少一次桥边。

  1 #include <iostream>
  2 #include <cmath>
  3 #include <vector>
  4 #include <cstdlib>
  5 #include <cstdio>
  6 #include <cstring>
  7 #include <queue>
  8 #include <stack>
  9 #include <list>
 10 #include <algorithm>
 11 #include <map>
 12 #include <set>
 13 #define LL long long
 14 #define Pr pair<int,int>
 15 
 16 using namespace std;
 17 const int INF=0x3f3f3f3f;
 18 const int msz=100000;
 19 const int mod=1e9+7;
 20 const double eps=1e-8;
 21 
 22 struct Edge
 23 {
 24     int v,next;
 25 };
 26 
 27 Edge eg[666666];
 28 int head[233333];
 29 int dfn[233333],low[233333];
 30 int pre[233333];
 31 int fa[233333];
 32 bool vis[233333];
 33 int tp,tim;
 34 int ans;
 35 
 36 void init(int n)
 37 {
 38     for(int i=1;i<=n;i++)
 39         pre[i]=i;
 40 }
 41 
 42 int Find(int x)
 43 {
 44     return pre[x]==x?x:pre[x]=Find(pre[x]);
 45 }
 46 
 47 int Union(int u,int v)
 48 {
 49     int k=Find(u);
 50     int r=Find(v);
 51     if(k==r) return false;
 52     pre[k]=r;
 53     return true;
 54 }
 55 
 56 void Tarjan(int u,int p)
 57 {
 58     vis[u]=1;
 59     dfn[u]=low[u]=tim++;
 60     int v;
 61     
 62     for(int i=head[u];i!=-1;i=eg[i].next)
 63     {
 64         v=eg[i].v;
 65         if(v==p) continue;
 66         
 67         if(!vis[v])
 68         {
 69             fa[v]=u;
 70             Tarjan(v,u);
 71             low[u]=min(low[u],low[v]);
 72             
 73             if(low[v]>dfn[u])
 74             {
 75                 ans++;
 76             }
 77             else
 78                 Union(v,u);
 79         }
 80         else low[u]=min(low[u],dfn[v]);
 81     }
 82 }
 83 
 84 void lca(int u,int v)
 85 {
 86     if(dfn[v]<dfn[u]) swap(u,v);
 87     
 88     while(dfn[v]>dfn[u])
 89     {
 90         if(Union(v,fa[v]))
 91             ans--;
 92         v=fa[v];
 93     }
 94     
 95     while(v!=u)
 96     {
 97         if(Union(u,fa[u]))
 98             ans--;
 99         u=fa[u];
100     }
101 }
102 
103 int main()
104 {
105     int n,m,u,v,z=0;
106     
107     while(scanf("%d%d",&n,&m),n+m)
108     {
109         memset(head,-1,sizeof(head));
110         tim=tp=0;
111         init(n);
112         
113         while(m--)
114         {
115             scanf("%d%d",&u,&v);
116             eg[tp].v=v;
117             eg[tp].next=head[u];
118             head[u]=tp++;
119             
120             eg[tp].v=u;
121             eg[tp].next=head[v];
122             head[v]=tp++;
123         }
124         
125         memset(vis,0,sizeof(vis));
126         ans=0;
127         fa[1]=1;
128         Tarjan(1,1);
129         
130         int q;
131         scanf("%d",&q);
132         
133         printf("Case %d:\n",++z);
134         
135         while(q--)
136         {
137             scanf("%d%d",&u,&v);
138             lca(u,v);
139             printf("%d\n",ans);
140         }
141         puts("");
142     }
143     return 0;
144 }
View Code

 

poj,3713

判断三联通问题,先删除一个点,然后求是否存在割点,如果存在则不是三联通。

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <algorithm>
  5 
  6 using namespace std;
  7 
  8 #define maxn 505
  9 
 10 struct edge
 11 {
 12     int v,next;
 13 };
 14 
 15 edge E[200005];
 16 int head[maxn];
 17 int dfn[maxn],low[maxn];
 18 int vis[maxn];
 19 int tp,tim;
 20 int n,m;
 21 bool has_cut_vertex;
 22 int root;
 23 
 24 void add_edge(int u,int v)
 25 {
 26     E[tp].v=v;
 27     E[tp].next=head[u];
 28     head[u]=tp++;
 29 }
 30 
 31 void Tarjan(int u,int p)//求割点/判断是否联通
 32 {
 33     vis[u]=1;
 34     dfn[u]=low[u]=++tim;
 35     
 36     int v;
 37     int child=0;
 38     
 39     for(int i=head[u];i!=-1;i=E[i].next)
 40     {
 41         v=E[i].v;
 42         if(v==p) continue;
 43         
 44         if(!vis[v])
 45         {
 46             Tarjan(v,u);
 47             child++;
 48             low[u]=min(low[u],low[v]);
 49             
 50             if((u==root && child>1) || (u!=root && low[v]>=dfn[u]))
 51                 has_cut_vertex=true;
 52         }
 53         else if(v!=p && vis[v]==1)
 54             low[u]=min(low[u],dfn[v]);
 55     }
 56     vis[u]=2;
 57 }
 58 
 59 void calc(int u)
 60 {//初始化
 61     memset(vis,0,sizeof(vis));
 62     memset(dfn,0,sizeof(dfn));
 63     memset(low,0,sizeof(low));
 64     //每次删除一个点,然后再看有无割点,如果删除一个点之后有割点,说明小于三联通。
 65     root=0;
 66     if(u==0)
 67     {
 68         root=1;
 69     }
 70     vis[u]=2;
 71     Tarjan(root,-1);
 72 }
 73 
 74 bool solve()
 75 {
 76     for(int i=0;i<n;i++)
 77     {
 78         calc(i);
 79         
 80         for(int j=0;j<n;j++)
 81             if(vis[j]==0)//如果存在孤立点也不是三联通
 82             {
 83                 has_cut_vertex=true;
 84                 break;
 85             }
 86         if(has_cut_vertex)
 87             break;
 88     }
 89     return !has_cut_vertex;
 90 }
 91 
 92 int main()
 93 {
 94     int u,v;
 95     while(scanf("%d%d",&n,&m),n+m)
 96     {
 97         tp=tim=0;
 98         memset(head,-1,sizeof(head));
 99         for(int i=0;i<m;i++)
100         {
101             scanf("%d%d",&u,&v);
102             add_edge(u,v);
103             add_edge(v,u);
104         }
105         
106         has_cut_vertex=false;
107         if(solve())
108             printf("YES\n");
109         else
110             printf("NO\n");
111     }
112     return 0;
113 }
View Code

 

 

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 
  5 using namespace std;
  6 
  7 #define maxn 505
  8 
  9 struct edge
 10 {
 11     int v,next;
 12 };
 13 
 14 edge E[200005];
 15 int head[maxn];
 16 int dfn[maxn],low[maxn];
 17 int vis[maxn];
 18 int tp;
 19 int n,m;
 20 bool has_cut_vertex;
 21 int root;
 22 
 23 void add_edge(int u,int v)
 24 {
 25     E[tp].v=v;
 26     E[tp].next=head[u];
 27     head[u]=tp++;
 28 }
 29 
 30 void Tarjan(int u,int p,int depth)
 31 {
 32     vis[u]=1;
 33     dfn[u]=low[u]=depth;
 34     
 35     int v;
 36     int child=0;
 37     
 38     for(int i=head[u];i!=-1;i=E[i].next)
 39     {
 40         v=E[i].v;
 41         if(v==p) continue;
 42         
 43         if(!vis[v])
 44         {
 45             Tarjan(v,u,depth+1);
 46             child++;
 47             low[u]=min(low[u],low[v]);
 48             
 49             if((u==root && child>1) || (u!=root && low[v]>=dfn[u]))
 50                 has_cut_vertex=true;
 51         }
 52         else if(v!=p && vis[v]==1)
 53             low[u]=min(low[u],dfn[v]);
 54     }
 55     vis[u]=2;
 56 }
 57 
 58 void calc(int u)
 59 {
 60     memset(vis,0,sizeof(vis));
 61     memset(dfn,0,sizeof(dfn));
 62     memset(low,0,sizeof(low));
 63     
 64     root=0;
 65     if(u==0)
 66     {
 67         root=1;
 68     }
 69     vis[u]=2;
 70     Tarjan(root,-1,1);
 71 }
 72 
 73 bool solve()
 74 {
 75     for(int i=0;i<n;i++)
 76     {
 77         calc(i);
 78         
 79         for(int j=0;j<n;j++)
 80             if(vis[j]==0)
 81             {
 82                 has_cut_vertex=true;
 83                 break;
 84             }
 85         if(has_cut_vertex)
 86             break;
 87     }
 88     return !has_cut_vertex;
 89 }
 90 
 91 int main()
 92 {
 93     int u,v;
 94     while(scanf("%d%d",&n,&m),n+m)
 95     {
 96         tp=0;
 97         memset(head,-1,sizeof(head));
 98         for(int i=0;i<m;i++)
 99         {
100             scanf("%d%d",&u,&v);
101             add_edge(u,v);
102             add_edge(v,u);
103         }
104         
105         has_cut_vertex=false;
106         if(solve())
107             printf("YES\n");
108         else
109             printf("NO\n");
110     }
111     return 0;
112 }
View Code

 

 

poj,3177

有详解:

一开始是联通图,然后问加多少边,使得整个图变成双联通。

求出桥,删除桥边,得出的联通块为双联通分量,收缩块,然后求出得到的树加多少边变成双联通图,至少(lead+1)/2。

如果用临接表建边不需要考虑重边问题;

如果用临接矩阵建边要考虑重边问题:但是我们可以在建边的时候不把重边建进去,然后依旧用low来划分双联通。

注意:low值相等说明在同一个双联通分量块里面,不等则度数加一,然后判断叶子节点的个数最后求解。

 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 
 7 #define maxn 5050
 8 
 9 struct edge
10 {
11     int v,next;
12 };
13 
14 using namespace std;
15 edge E[10010];
16 int head[maxn];
17 int n,m,tp,t,ans;
18 int dfn[maxn],low[maxn];
19 bool map[maxn][maxn];
20 
21 void add_edge(int u,int v)
22 {
23     E[tp].v=v;
24     E[tp].next=head[u];
25     head[u]=tp++;
26 }
27 
28 void Tarjan(int u,int p)
29 {
30     dfn[u]=low[u]=++t;
31     for(int i=head[u];i!=-1;i=E[i].next)
32     {
33         int v=E[i].v;
34         
35         if(!dfn[v])//如果为树边
36         {
37             Tarjan(v,u);
38             low[u]=min(low[u],low[v]);
39         }
40         else if(v!=p)//不走回头路且为后向边
41         {
42             low[u]=min(low[u],dfn[v]);
43         }
44     }
45     
46 }
47 
48 void output()
49 {
50     int cnt[maxn],num=0;
51     memset(cnt,0,sizeof(cnt));
52     
53     for(int i=1;i<=n;i++)
54         for(int j=head[i];j!=-1;j=E[j].next)
55         {
56             int v=E[j].v;
57             if(low[v]!=low[i])
58                 cnt[low[i]]++; //求出每个点的度,当成有向图求。如果无向图则最后判断,度要除以2
59         }
60     
61     for(int i=0;i<=n;i++)
62         if(cnt[i]==1)
63             num++;
64     printf("%d\n",(num+1)/2);
65 }
66 
67 int main()
68 {
69     scanf("%d%d",&n,&m);
70     memset(head,-1,sizeof(head));
71     memset(map,false,sizeof(map));//记录重边
72     memset(dfn,0,sizeof(dfn));//第一次访问。
73     tp=t=0;
74     
75     int a,b;
76     for(int i=0;i<m;i++)
77     {
78         scanf("%d%d",&a,&b);
79         if(!map[a][b])
80         {
81             add_edge(a,b);
82             add_edge(b,a);
83             map[a][b]=map[b][a]=true;
84         }
85     }
86     Tarjan(1,1);
87     output();
88     return 0;
89 }
View Code

 

uva,10765

一个鸽子把信息从最高指挥部带出到一个station然后这个信息会被火车送往其他未被轰炸的地方,求轰炸完一个station至少需要放多少只鸽子把所有未轰炸的station都通知到。

一开始的想法就是:所有的点初始化鸽子数为1,然后求出割点计算与之相连的联通块个数然后排序输出题目要求的炸弹数就可以了。

注意每个station最多与另外10个station直接相连,所以建临接表要注意区间= =?

然后就是输出格式。。。我真的见了你的鬼了。

 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 
 7 #define maxn 10010
 8 
 9 struct edge
10 {
11     int v,next;
12 };
13 struct node
14 {
15     int cnt,u;
16 };
17 
18 
19 using namespace std;
20 edge E[10*maxn+5];//注意最多有十条边相连,对于每个点/re了几次?
21 node G[maxn];
22 int head[maxn];
23 int n,m,tp,t,ans;
24 int dfn[maxn],low[maxn];
25 
26 void add_edge(int u,int v)
27 {
28     E[tp].v=v;
29     E[tp].next=head[u];
30     head[u]=tp++;
31 }
32 
33 bool cmp(node a,node b)//题目要求排序
34 {
35     if(a.cnt==b.cnt) return a.u<b.u;
36     return a.cnt>b.cnt;
37 }
38 void Tarjan(int u,int p)//求割点
39 {
40     dfn[u]=low[u]=++t;
41     
42     int child=0;
43     for(int i=head[u];i!=-1;i=E[i].next)
44     {
45         int v=E[i].v;
46         if(v==p) continue;
47         if(!dfn[v])
48         {
49             Tarjan(v,u);
50             child++;
51             low[u]=min(low[u],low[v]);
52             
53             if((u==p && child>1) || (u!=p && low[v]>=dfn[u]))
54                 G[u].cnt++;//把割点和与之相连的边去掉之后能形成几个联通块
55         }
56         else if(v!=p)
57         {
58             low[u]=min(low[u],dfn[v]);
59         }
60     }
61     
62 }
63 
64 void output()
65 {
66     sort(G,G+n,cmp);//打印输出前m个数值
67     for(int i=0;i<m;i++)
68         printf("%d %d\n",G[i].u,G[i].cnt);
69 }
70 
71 int main()
72 {
73    while(scanf("%d%d",&n,&m),n+m)
74    {
75        memset(head,-1,sizeof(head));
76        memset(dfn,0,sizeof(dfn));
77        memset(low,0,sizeof(low));
78        for(int i=0;i<n;i++)
79        {
80            G[i].u=i;
81            G[i].cnt=1;
82        }
83        tp=t=0;
84     
85        int a,b;
86        while(scanf("%d%d",&a,&b),(a+b)!=-2)
87        {
88            add_edge(a,b);
89            add_edge(b,a);
90        }
91        Tarjan(0,0);
92        output();
93        printf("\n");
94    }
95     return 0;
96 }
View Code

 

转载于:https://www.cnblogs.com/do-it-best/p/5483392.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值