边双联通分量
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
输出
4
4
4
6
7
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 */
后来知道是边双联通分量。。
概念:任意两点至少存在两条边不重复路径
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 }
以上是关于边双联通分量的主要内容,如果未能解决你的问题,请参考以下文章