【poj3522-苗条树】最大边与最小边差值最小的生成树,并查集
2016-11-08 11:27
471 查看
题意:求最大边与最小边差值最小的生成树。n<=100,m<=n*(n-1)/2,没有重边和自环。
题解:
m^2的做法就不说了。
时间复杂度O(n*m)的做法:
按边排序,枚举当前最大的边。
那也就是说,把边排序之后从小到大编号,要在[1,r]这段区间内生成一棵最大边与最小边差值最小的生成树。
那每次生成肯定不行(这就是暴力m^2做法。。),我们考虑继承。
假设[1,r-1]这段区间内的苗条树已经生成,那我们只需要把当前第r条边加进去。
加进去分两种情况:
x和y还没有联通:直接加边
x和y已经联通:这样树上就形成了一个环,我们把环上最小的边删除,那就是当前的苗条树。
我维护一个fa[x]表示x节点的fa是谁,dis[x]表示x节点到fa节点的距离。
找环:
先不把那条边加进去,在x,y暴力不断fa上跳找出lca。x->lca->y->x就是那个环。
一开始lca那里错了。。
暴力找lca:
删边:
这道题涉及删边丫。。又要n*m做出来。。
fa[]其实就是一条有向边,其实我们只需要修改fa[]和dis[]就可以了。
我就t0表示那个fa[id]所代表的有向边是要删除的 是在x还是y。
具体看代码把。。注意暴栈(我也不知道为什么),就改成了数组+while。
题解:
m^2的做法就不说了。
时间复杂度O(n*m)的做法:
按边排序,枚举当前最大的边。
那也就是说,把边排序之后从小到大编号,要在[1,r]这段区间内生成一棵最大边与最小边差值最小的生成树。
那每次生成肯定不行(这就是暴力m^2做法。。),我们考虑继承。
假设[1,r-1]这段区间内的苗条树已经生成,那我们只需要把当前第r条边加进去。
加进去分两种情况:
x和y还没有联通:直接加边
x和y已经联通:这样树上就形成了一个环,我们把环上最小的边删除,那就是当前的苗条树。
我维护一个fa[x]表示x节点的fa是谁,dis[x]表示x节点到fa节点的距离。
找环:
先不把那条边加进去,在x,y暴力不断fa上跳找出lca。x->lca->y->x就是那个环。
一开始lca那里错了。。
暴力找lca:
1 int find_lca(int x,int y) 2 { 3 memset(inx,0,sizeof(inx)); 4 memset(iny,0,sizeof(iny)); 5 int t=0,k=0; 6 while(x) t++,inx[x]=t,x=fa[x]; 7 while(y) k++,iny[y]=k,y=fa[y]; 8 int z=0; 9 for(int i=1;i<=n;i++) 10 { 11 if(inx[i] && iny[i]) 12 { 13 if(z==0) z=i; 14 else if(inx[i]<inx[z] || iny[i]<iny[z]) z=i; 15 } 16 } 17 return z; 18 }
删边:
这道题涉及删边丫。。又要n*m做出来。。
fa[]其实就是一条有向边,其实我们只需要修改fa[]和dis[]就可以了。
我就t0表示那个fa[id]所代表的有向边是要删除的 是在x还是y。
具体看代码把。。注意暴栈(我也不知道为什么),就改成了数组+while。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 8 const int N=400,M=2*200010,INF=(int)1e9; 9 struct node{ 10 int x,y,d,next,bk; 11 }a[M]; 12 int n,m,t0,t1,id,f ,fa ,dis ,inx ,iny ,c ,p ; 13 14 bool cmp(node x,node y){return x.d<y.d;} 15 int maxx(int x,int y){return x>y ? x:y;} 16 int minn(int x,int y){return x<y ? x:y;} 17 18 int findfa(int x) 19 { 20 if(f[x]==x) return f[x]; 21 return findfa(f[x]); 22 } 23 24 int find_lca(int x,int y) 25 { 26 memset(inx,0,sizeof(inx)); 27 memset(iny,0,sizeof(iny)); 28 int t=0,k=0; 29 while(x) t++,inx[x]=t,x=fa[x]; 30 while(y) k++,iny[y]=k,y=fa[y]; 31 int z=0; 32 for(int i=1;i<=n;i++) 33 { 34 if(inx[i] && iny[i]) 35 { 36 if(z==0) z=i; 37 else if(inx[i]<inx[z] || iny[i]<iny[z]) z=i; 38 } 39 } 40 return z; 41 } 42 43 void find_min(int x,int y,int z) 44 { 45 int mn=INF,xx=x,yy=y; 46 while(x!=z) 47 { 48 if(dis[x]<mn) mn=dis[x],id=x,t0=xx,t1=yy; 49 x=fa[x]; 50 } 51 while(y!=z) 52 { 53 if(dis[y]<mn) mn=dis[y],id=y,t0=yy,t1=xx; 54 y=fa[y]; 55 } 56 } 57 58 void change(int x,int pre) 59 { 60 int pl=0; 61 c[++pl]=x;p[pl]=pre; 62 while(x && x!=id) 63 { 64 c[++pl]=fa[x];p[pl]=x; 65 x=fa[x]; 66 } 67 for(int i=pl;i>=1;i--) 68 { 69 fa[c[i]]=p[i]; 70 dis[c[i]]=dis[p[i]]; 71 } 72 } 73 74 int main() 75 { 76 freopen("a.in","r",stdin); 77 freopen("a.out","w",stdout); 78 while(1) 79 { 80 scanf("%d",&n); 81 if(!n) return 0; 82 scanf("%d",&m); 83 memset(fa,0,sizeof(fa)); 84 memset(dis,0,sizeof(dis)); 85 for(int i=1;i<=n;i++) f[i]=i; 86 for(int i=1;i<=m;i++) 87 { 88 scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].d); 89 a[i].x++,a[i].y++; 90 } 91 sort(a+1,a+1+m,cmp); 92 int x,y,z,d,mn,cnt=0,ans=INF; 93 for(int i=1;i<=m;i++) 94 { 95 x=a[i].x,y=a[i].y,d=a[i].d; 96 if(findfa(x)!=findfa(y)) 97 { 98 cnt++; 99 id=0;change(x,y); 100 dis[x]=d; 101 f[findfa(x)]=findfa(y); 102 } 103 else 104 { 105 z=find_lca(x,y); 106 find_min(x,y,z); 107 change(t0,t1); 108 dis[t0]=d; 109 } 110 if(cnt>=n-1) 111 { 112 mn=INF; 113 for(int j=1;j<=n;j++) 114 if(fa[j]) mn=minn(mn,dis[j]); 115 ans=minn(ans,d-mn); 116 } 117 } 118 printf("%d\n",ans); 119 } 120 return 0; 121 }
相关文章推荐
- poj3522(求最大边最小边差值最小的生成树)
- POJ3522Slim Span(最大边与最小边差值最小的生成树)
- POJ 3522 最大边与最小边差值最小的生成树
- POJ3522 SlimSpan 最大边和最小边的差最小的生成树
- POJ3522差值最小的生成树
- POJ 3522 最大边与最小边差值最小的生成树(最小生成树的性质)
- 利用并查集求最大生成树和最小生成树(nlogn)
- 利用并查集求最大生成树和最小生成树(nlogn)
- Slim Span 求一颗生成树 使得最大边与最小边的差值最小
- POJ 3264 Balanced Lineup(最大最小差值 线段树水题)
- POJ 3522 - Slim Span 求一颗生成树,让最大边最小边差值最小
- 找出一个数组中两个数的最大差值和最小差值(最接近的数)
- hdoj 3367 Pseudoforest 【伪森林】 【并查集判断环 + 最大生成树】
- 阿里14笔试题-求一个二叉树最大值和最小值的差值绝对值
- NOIP 边权差值最小的生成树(小数据)
- Poj 3522 最长边与最短边差值最小的生成树
- ZOJ 3649 Social Net 最大生成树 + 并查集维护
- 天气晴朗的魔法 大+小生成树(最大值最小)/二分
- 阿里14笔试题-求一个二叉树最大值和最小值的差值绝对值
- hdu 4786 最小生成树与最大生成树