边双联通分量

Posted HWIM

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了边双联通分量相关的知识,希望对你有一定的参考价值。

(noip模拟赛)化学竞赛的大奖

(prize.pas/c/cpp)


【问题描述】


XYX 在 CChO(全国化学奥林匹克竞赛)比赛中获得了大奖,奖品是一张特殊的机票。
使用这张机票,可以在任意一个国家内的任意城市之间的免费飞行,只有跨国飞行时才
会有额外的费用。XYX 获得了一张地图,地图上有城市之间的飞机航班和费用。已知从
每个城市出发能到达所有城市,两个城市之间可能有不止一个航班。一个国家内的每两
个城市之间一定有不止一条飞行路线, 而两个国家的城市之间只 有一条飞行路线。 XYX
想知道, 从每个城市出发到额外费用最大的城市, 以便估算出出行的费用, 请你帮助他。
当然,你不能通过乘坐多次一个航班增加额外费用, 也就是必须沿费用最少的路线飞
行。


【输入】


第一行,两个整数 N,M,表示地图上有 N 个城市,M 条航线。
接下来 M 行,每行三个整数 a,b,c,表示城市 a,b 之间有一条费用为 c 的航线。


【输出】

共 N 行,第 i 行为从城市 i 出发到达每个城市额外费用的最大值。


【输入输出样例 1】

输入

6 6 
1 4 2 
1 2 6 
2 5 3 
2 3 7 
6 3 4 
3 1 8

输出






7


有四个国家,包含的城市分别为 {1,2,3},{4},{5},{6}。
从城市 1 出发到达城市 6,乘坐(1,3)(3,6)两个航班费用最大,
(1,3)在国内为免费航班,(3,6)的费用为 4,所以从 1 出发的最
大费用为 4。


【数据范围】


对于 40%的数据 1<=N<=1000,1<=M<=1000
对于 100%的数据 1<=N<=20000,1<=M<=200000

 

分析

模拟赛的一道题,感觉像tarjan缩点,但这是无向图,

但是思想是一样的,所以写了一个乱搞的tarjan,居然a了。。

技术分享图片
  1 #include<cstdio>
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstring>
  5 
  6 using namespace std;
  7 
  8 const int N = 50010;
  9 const int M = 500100;
 10 
 11 struct Edge{
 12     int to,w,nxt;
 13     bool flag;
 14     Edge() {flag = false;}
 15 }e[M],t[M];
 16 int head[N],tot = 1,headt[N],tott;
 17 int dfn[N],low[N],st[N],top;
 18 int bel[N],dp[N][3],ans[N];
 19 bool vis[N];
 20 int tn,cnt;
 21 
 22 inline int read() {
 23     int x = 0,f =1;char ch = getchar();
 24     for (; ch<0||ch>9; ch = getchar())
 25         if (ch==-) f = -1;
 26     for (; ch>=0&&ch<=9; ch = getchar())
 27         x = x*10+ch-0;
 28     return x*f;
 29 }
 30 
 31 
 32 void tarjan(int u,int fa) {
 33     dfn[u] = low[u] = ++tn;
 34     st[++top] = u;
 35     vis[u] = true;
 36     
 37     for (int i=head[u]; i; i=e[i].nxt) {
 38         int v = e[i].to;
 39         if (!dfn[v]) {
 40             e[i^1].flag = true;
 41             tarjan(v,u);
 42             low[u] = min(low[u],low[v]);
 43         }
 44         else {
 45             if (vis[v] && !e[i].flag) low[u] = min(low[u],dfn[v]);
 46         }
 47     }
 48     
 49     if (dfn[u]==low[u]) {
 50         ++cnt;
 51         do {
 52             vis[st[top]] = false;
 53             bel[st[top]] = cnt;
 54             top--;            
 55         }while (st[top+1]!=u);
 56     }
 57 }
 58 
 59 
 60 inline void add_edge(int u,int v,int w) {
 61     t[++tott].to = v,t[tott].w = w,t[tott].nxt = headt[u],headt[u] = tott;
 62     t[++tott].to = u,t[tott].w = w,t[tott].nxt = headt[v],headt[v] = tott;
 63 }
 64 
 65 void dfs(int u,int fa) {
 66     int ts = headt[u];
 67     for (int i=headt[u]; i; i=t[i].nxt) {
 68         int v = t[i].to;
 69         if (v==fa) continue;
 70         if (vis[v]) continue;
 71         vis[v] = true;
 72         dfs(v,u);
 73         if (dp[v][0] + t[i].w > dp[u][0]) {
 74             dp[u][1] = dp[u][0];
 75             dp[u][0] = dp[v][0]+t[i].w;
 76         }
 77         else if (dp[v][0]+t[i].w > dp[u][1]) 
 78             dp[u][1] = dp[v][0]+t[i].w;
 79     }
 80 }
 81 void dfs2(int u,int fa) {
 82     
 83     for (int i=headt[u]; i; i=t[i].nxt) {
 84         int v = t[i].to;
 85         if (v==fa) continue;
 86         if (vis[v]) continue;
 87         vis[v] = true;
 88         if (dp[v][0]+t[i].w==dp[u][0]) 
 89             dp[v][2] = max(dp[u][2],dp[u][1])+t[i].w;
 90         else dp[v][2] = max(dp[u][2],dp[u][0])+t[i].w;
 91         dfs2(v,u);
 92     }
 93 }
 94 
 95 int main() {
 96     
 97     freopen("prize.in","r",stdin);
 98     freopen("prize.out","w",stdout);
 99     
100     int n = read(),m = read();
101     for (int u,v,w,i=1; i<=m; ++i) {
102         u = read(),v = read(),w = read();
103         e[++tot].to = v,e[tot].w = w,e[tot].nxt = head[u],head[u] = tot;
104         e[++tot].to = u,e[tot].w = w,e[tot].nxt = head[v],head[v] = tot;
105     }
106     
107     /*for (int i=1; i<=n; ++i) 
108         if (!dfn[i]) */
109     tarjan(1,0);
110     
111 //    for (int i=1; i<=n; ++i) printf("%d ",bel[i]);    
112     for (int i=1; i<=n; ++i) 
113         for (int j=head[i]; j; j=e[j].nxt) 
114             add_edge(bel[i],bel[e[j].to],e[j].w);
115     
116 /*    for (int i=1; i<=4; ++i) {
117         printf("%d",headt[i]);
118     //    for (int j=headt[i]; j; j=t[j].nxt) 
119     //        printf("%d ",t[j].to);
120         printf("\n");
121         
122     }*/
123     memset(vis,false,sizeof(vis));
124     vis[1] = true;
125     dfs(1,0);
126     memset(vis,false,sizeof(vis));
127     vis[1] = true;
128     dfs2(1,0);
129     
130     for (int i=1; i<=cnt; ++i) 
131         ans[i] = max(dp[i][0],dp[i][2]);
132 
133     for (int i=1; i<=n; ++i) 
134         printf("%d\n",ans[bel[i]]);
135     return 0;
136 }
137 /*
138 
139 6 6
140 1 4 2
141 1 2 6
142 2 5 3
143 2 3 7
144 6 3 4
145 3 1 8
146 
147 
148 6 6
149 1 2 1
150 2 3 1
151 2 4 1
152 3 5 1
153 4 5 1
154 5 6 1
155 
156 6 7
157 1 2 3
158 2 3 1
159 3 4 1
160 4 5 1
161 2 5 1
162 4 2 1
163 4 6 2
164 
165 7 9
166 1 2 3
167 2 3 1
168 3 4 1
169 4 5 1
170 2 5 1
171 4 2 1
172 4 6 2
173 3 7 1
174 4 7 1
175 
176 */
View Code

后来知道是边双联通分量。。

概念:任意两点至少存在两条边不重复路径

技术分享图片
  1 #include<bits/stdc++.h>
  2 #define maxn 20005
  3 #define maxm 200005
  4 using namespace std;
  5 
  6 int n,m,id,dfn[maxn],low[maxn],head[maxn],head2[maxn],cnt;
  7 int dis[maxn],dis1[maxn],mx=0,root;
  8 int belong[maxn],belnum;
  9 bool vis[maxn];
 10 stack<int> stk;
 11 struct Edge{    
 12 int u,v,val,next;
 13 }edge[maxm<<1],e[maxm<<1];
 14 
 15 inline int read()
 16 {
 17     int x=0,f=1;char c=getchar();
 18     while(c<0||c>9){if(c==-)f=-1;c=getchar();}
 19     while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}
 20     return x*f;
 21 }
 22 namespace Tarjan
 23 { 
 24 
 25 inline void add(int u,int v,int val)
 26 {    
 27     edge[++cnt].v=v;    
 28     edge[cnt].u=u;    
 29     edge[cnt].val=val;    
 30     edge[cnt].next=head[u];    
 31     head[u]=cnt;
 32 } 
 33 
 34 inline void tarjan(int u,int fa)
 35 {    
 36     dfn[u]=low[u]=++id;    
 37     vis[u]=1;    
 38     stk.push(u);    
 39     for(int i=head[u];i!=-1;i=edge[i].next)    
 40     {    
 41         int v=edge[i].v;    
 42         if(!dfn[v])    
 43         {    
 44             tarjan(v,u);    
 45             low[u]=min(low[u],low[v]);    
 46         }    
 47         else if(vis[v]&&v!=fa)    
 48         {    
 49             low[u]=min(low[u],dfn[v]);    
 50         }    
 51     }    
 52     if(dfn[u]==low[u])    
 53     {    
 54         belnum++;    
 55         int temp;    
 56         do{    
 57             temp=stk.top();    
 58             belong[temp]=belnum;    
 59             vis[temp]=0;    
 60             stk.pop();    
 61         }while(temp!=u);    
 62     }
 63 } 
 64 
 65 inline void solve1()
 66 {    
 67     memset(head,-1,sizeof(head));    
 68     for(int i=1,u,v,val;i<=m;i++)    
 69     {    
 70         u=read();v=read();val=read();    
 71         add(u,v,val);add(v,u,val);    
 72     }    
 73     for(int i=1;i<=n;i++)    
 74     {    
 75         if(!dfn[i])    tarjan(i,0);    
 76     }
 77 } 
 78 
 79 } 
 80 
 81 namespace LP
 82 { 
 83 
 84 inline void Add(int u,int v,int val)
 85 {    
 86     e[++cnt].v=v;    
 87     e[cnt].val=val;    
 88     e[cnt].next=head2[u];    
 89     head2[u]=cnt;
 90 } 
 91 
 92 void dfs1(int u,int fa)
 93 {    
 94     for(int i=head2[u];i!=-1;i=e[i].next)    
 95     {    
 96         int v=e[i].v;    
 97         if(v==fa)    continue;    
 98         dis[v]=dis[u]+e[i].val;    
 99         if(dis[v]>mx)    mx=dis[v],root=v;    
100         dfs1(v,u);    
101     }
102 } 
103 
104 void dfs2(int u,int fa)
105 {    
106     for(int i=head2[u];i!=-1;i=e[i].next)    
107     {    
108         int v=e[i].v;    
109         if(v==fa)    continue;    
110         dis1[v]=dis1[u]+e[i].val;    
111         dfs2(v,u);    
112     }
113 } 
114 
115 inline void solve2()
116 {    
117     cnt=0;    
118     memset(head2,-1,sizeof(head2));    
119     for(int i=1;i<=n;i++)    
120         for(int j=head[i];j!=-1;j=edge[j].next)    
121         {    
122             if(belong[i]!=belong[edge[j].v])    
123                 Add(belong[i],belong[edge[j].v],edge[j].val);    
124         }    
125     dfs1(1,-1);    
126     mx=0;memset(dis,0,sizeof(dis));    
127     dfs1(root,-1);    
128     mx=0;    
129     dfs2(root,-1);    
130     for(int i=1;i<=n;i++)    
131         printf("%d\n",max(dis[belong[i]],dis1[belong[i]]));
132 } 
133     
134 }
135 int main()
136 {    
137     freopen("prize.in","r",stdin);
138     freopen("prize.out","w",stdout);
139     n=read();m=read();    
140     Tarjan::solve1();    
141     LP::solve2();    
142     return 0;
143 }
View Code

 

以上是关于边双联通分量的主要内容,如果未能解决你的问题,请参考以下文章

边双联通分量

POJ 1515 双联通分量

双联通的tarjan算法

POJ 3694Network(Tarjan边双联通分量 + 缩点 + LCA并查集维护)

边双联通分量

poj-3177(并查集+双联通分量+Tarjan算法)