CodeForces 160D Edges in MST 题解
来源:互联网 发布:mac打字卡顿 编辑:程序博客网 时间:2024/06/11 01:04
[题意]
给出一个n个点m条边的无向连通图,判断图中每条边是否一定在最小生成树上.
n,m<=100000.
[思路]
由于最小生成树的性质,我们造出任意一棵最小生成树,并记录下与最小生成树权值相等的所有边.
暴力版:
沿着非树边x的两个端点走到它们的lca,在环上去找与x权值相同的边,如果找到,说明被替换的边和x都不一定在最小生成树上.
暴力做法优化版:
这里又有一个结论:
如果x能替换边y,那么y一定是x在最小生成树上组成的环中权值最大的边.那么我们只要把边按照边权值从小到大排序,再用并查集路径压缩,(类似删边最小生成树的做法),可以更高效.
“桥”版:
题目中提到了”一定在最小生成树上的边”,也就是说没有这条边,最小生成树就不会联通,这就和”桥”的概念很像.如何判断每条边呢?
我们按照kruskal算法,按照边权值枚举边,并查集判断联通情况,把权值相同的边放在一起:如果有一条边(权值为x)在加入树之前,两个端点已经并在一个集合里,说明有更小的边权就能使两点联通,那么这条边一定是无效的.
现在我们要判断的就是桥边了.
我们把权值为x的所有边(除了无效边)加入目前的图里,对于每一个联通块, 用tarjan算法判断桥边.再把权值为x的每条边用并查集合并到联通块里.
暴力版:
<span style="font-size:18px;">#include<cstdio>#include<iostream>#include<algorithm>#include<vector>#define ll long longusing namespace std;inline void rd(int &res){ res=0;char c; while(c=getchar(),c<48); do{ res=(res<<1)+(res<<3)+(c^48); }while(c=getchar(),c>=48);}inline void print(int k){ if(k==0)return ; print(k/10); putchar((k%10)^48);}inline void sc(int k){ print(k); if(k==0)putchar('0'); putchar('\n');}const int M=1e5+5;const int oo=1e9;const int S=18;int L[M],R[M],dep[M],fa[M],cnt[M],ans[M],T=0,n,m,mark[M],eid[M],rfa[M][S],flag=0;vector<int>e[M],out[M];struct node{ int id,a,b,c;}ed[M];bool cmp(node a,node b){ return a.c<b.c;}int get(int x){ if(fa[x]!=x)fa[x]=get(fa[x]); return fa[x];}void dfs(int x,int f,int d){ dep[x]=d; L[x]=++T; rfa[x][0]=f; for(int i=0;i<e[x].size();i++){ int y=e[x][i]; if(y==f)continue; dfs(y,x,d+1); } R[x]=T;}void UP(int &a,int step){ for(int i=S-1;i>=0;i--){ if(step&(1<<i))a=rfa[a][i]; }}int LCA(int a,int b){ if(a==b)return a; if(dep[a]<dep[b])swap(a,b); UP(a,dep[a]-dep[b]); if(a==b)return a; for(int i=S-1;i>=0;i--){ if(rfa[a][i]!=rfa[b][i])a=rfa[a][i],b=rfa[b][i]; } return rfa[a][0];}void walk(int a,int lca,int id){ while(a!=lca){ if(ed[eid[a]].c==ed[id].c){ flag=1;ans[ed[eid[a]].id]=0; } a=rfa[a][0]; }}void chk(int id){ int a=ed[id].a,b=ed[id].b,c=ed[id].c; int lca=LCA(a,b); flag=0; walk(a,lca,id); walk(b,lca,id); if(flag)ans[ed[id].id]=0;}int main(){ int i,j,k,a,b,c,mx=oo,tot=0,pre=-1; scanf("%d %d",&n,&m); for(i=1;i<=m;i++){ rd(a);rd(b);rd(c); ed[i]=(node){i,a,b,c}; ans[i]=2; } for(i=1;i<=n;i++)fa[i]=i,cnt[i]=1; sort(ed+1,ed+1+m,cmp); for(i=1;i<=m;i++){ int a=ed[i].a,b=ed[i].b,c=ed[i].c; int x=get(a),y=get(b); if(c>mx)break; if(c!=pre){pre=c;tot++;} if(x!=y){ fa[x]=y; cnt[y]+=cnt[x]; e[a].push_back(b); e[b].push_back(a); mark[i]=1; ans[ed[i].id]=1; if(cnt[y]==n)mx=c; } } dfs(1,0,0); for(i=1;i<S;i++){ for(j=1;j<=n;j++)rfa[j][i]=rfa[rfa[j][i-1]][i-1]; } for(i=1;i<=m;i++){ int a=ed[i].a,b=ed[i].b; if(rfa[a][0]==b||rfa[b][0]==a){ int x=a; if(dep[b]>dep[a])x=b; eid[x]=i; } } for(i=1;i<=m;i++){ if(ed[i].c>mx)break; if(!mark[i])chk(i); } for(i=1;i<=m;i++)sc(ans[i]); return 0;<span style="font-family:Comic Sans MS;">}</span></span>
<span style="font-size:18px;">#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>using namespace std;const int M=100005;int ans[M],low[M],dfn[M],head[M],n,m,fa[M],tot=0,timestamp=0;struct node{ int to,nex,id;}e[M*2];struct edge{ int a,b,c,id;}ed[M];inline void rd(int &res){ res=0; char c; while(c=getchar(),c<48); do res=(res<<3)+(res<<1)+(c^48); while(c=getchar(),c>47);}void print(int x){ if(x==0)return ; print(x/10); putchar((x%10)^48);}void sc(int x){ print(x); if(x==0)putchar('0'); putchar('\n');}bool cmp(edge a,edge b){ return a.c<b.c;}int get(int x){ if(fa[x]!=x)fa[x]=get(fa[x]); return fa[x];}void dfs(int x,int id){ dfn[x]=low[x]=++timestamp; for(int i=head[x];~i;i=e[i].nex){ int to=e[i].to,eid=e[i].id; if(dfn[to]==0){ dfs(to,i); low[x]=min(low[x],low[to]); if(low[to]>dfn[x])ans[eid]=1;//是桥边 ,一定会在最小生成树中 } else if(dfn[to]<dfn[x]&&i!=(id^1))low[x]=min(low[x],low[to]); } //printf("%d %d %d\n",x,dfn[x],low[x]);}void add_edge(int a,int b,int id){//a,b之间加一条边 无向边要加两次 e[tot]=(node){b,head[a],id}; head[a]=tot++;}void get_union(int a,int b){ a=get(a);b=get(b); if(a!=b)fa[a]=b;}int main(){ int i,j,k,a,b,c,en; rd(n);rd(m); for(i=1;i<=m;i++){ rd(a);rd(b);rd(c); ed[i]=(edge){a,b,c,i}; } sort(ed+1,ed+1+m,cmp); for(i=1;i<=n;i++)fa[i]=i,head[i]=-1; for(i=1;i<=m;i++){ for(j=i;j<=m;j++){ if(ed[j+1].c!=ed[i].c)break; } en=j; for(j=i;j<=en;j++){ ed[j].a=a=get(ed[j].a); ed[j].b=b=get(ed[j].b); dfn[a]=0;dfn[b]=0; low[a]=0;low[b]=0; head[a]=-1;head[b]=-1; } for(j=i;j<=en;j++){ a=ed[j].a;b=ed[j].b; if(a==b){ans[ed[j].id]=2;continue;} add_edge(a,b,ed[j].id); add_edge(b,a,ed[j].id); } for(j=i;j<=en;j++){ if(!dfn[ed[j].a])dfs(ed[j].a,-1); if(!dfn[ed[j].b])dfs(ed[j].b,-1); } for(j=i;j<=en;j++){get_union(ed[j].a,ed[j].b);} i=en; } for(i=1;i<=m;i++)sc(ans[i]); return 0;}</span>
20160627离线赛/CodeForces 160D
1 0
- CodeForces 160D Edges in MST 题解
- Codeforces 160D Edges in MST
- [Codeforces]160D - Edges in MST
- codeforces 160D Edges in MST
- codeforces 160D - Edges in MST
- CodeForces 160D Edges in MST (tarjan)
- CF 160D Edges in MST
- CodeForces 160D - Edges in MST kruskal+tarjan求无向图的桥
- Codeforces 160D Edges in MST【思维+并查集+求桥(有重边)】
- Codeforces160D Edges in MST
- codeforces 594D题解
- Codeforces 625D Finals in arithmetic(Codeforces Round #342 (Div. 2) D) 题解
- Orientation of Edges CodeForces
- UVA 11747 - Heavy Cycle Edges(MST)
- UVA 11747 Heavy Cycle Edges(MST)
- codeforces D. Ice Sculptures 题解
- Codeforces 325D Reclamation 题解
- Codeforces 475D CGCDSSQ 题解
- ffmpeg study
- 柔性数组
- Code Walkthrough - HashMap
- 单缓冲 vs 双缓冲 处理数据时间计算方法
- Geotools读取shp文件并在Ol2中展示
- CodeForces 160D Edges in MST 题解
- 享元模式 详解
- Lintcode_11 Search Range in Binary Search Tree
- 矩阵乘法的经典题目_源自Matrix67_
- 获取APK签名sha1值
- Lintcode_16 Permutations II
- The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path
- Lintcode_18 Subsets II
- C# 怎样将DateTime类型进行日期的加减