【poj3522-苗条树】最大边与最小边差值最小的生成树,并查集
题意:求最大边与最小边差值最小的生成树。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:
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[N],fa[N],dis[N],inx[N],iny[N],c[N],p[N];
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 }