【题意】
给出N个点,M条边,问这N个点形成的生成树的最大权值边-最小权值边的最小值
Input
The input consists of several test cases, separated by single blank lines. Each test case begins with a
line containing the integer n (2 ≤ n ≤ 350), the number of doors in the building. The following line
contains another integer, m (n − 1 ≤ m ≤ n(n − 1)/2), the number of sensors in the network. The
test case finishes with m lines containing a description of each of the m sensors. The i-th of those lines
contains three integers, a (0 ≤ a ≤ n−1), b (0 ≤ b ≤ n−1) and w (1 ≤ w ≤ 2
15), in that order. Integers
a and b represent the pair of doors controlled by the i-th sensor, and w its recommended voltage. You
can safely assume that there are no two sensors controlling the same two doors.
The input will finish with a line containing ‘0’.
Output
For each case, your program should output a line containing the minimum margin of an admissible
subset of the sensors.
Sample Input
3
3
0 1 220
1 2 120
2 0 160
4
5
2 3 80
1 3 80
0 1 180
2 1 200
3 0 140
0
Sample Output
40
60
【分析】
是Uva1395的进化版。
数据范围大了一点点,不过之前的方法也是够慢的,m^2。
总结来说,生成树问题其实就是有一棵最小生成树,然后你sm乱枚举一些东西,然后在最小生成树上搞啊搞。。【难道不是么??..
最喜欢就是加一条边弄一个环然后在环上面又删一条边,就是没add边的时候两个点之间唯一路径上的边的权值求最值。
这题就是这样啦。
先排序,加边,考虑一下加下去的边是否会形成环,如果形成环的话,就把环内的最小边去掉(因为最长边就是现在ADD的那条边,如果要苗条就让边最小尽量大),然后重新求这棵新的生成树的最小边。等到生成树形成的时候,因为添加进去的新边的权值肯定是最大值的,所以只要只减去之前维护一个的最小值就可以了。
然后,求路径最小边还有找最短边都是O(n)暴力的。
总时间复杂度:O(nm)
之前的方法复杂度是O(m^2),嗯,很多恶心题就是完全图,如果是完全图的话,这样的方法无疑是更优的。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 #include<vector> 8 using namespace std; 9 #define Maxn 410 10 #define INF 0xfffffff 11 12 int n,m; 13 14 struct node 15 { 16 int x,y,c; 17 }t[Maxn*Maxn]; 18 19 bool cmp(node x,node y) {return x.c<y.c;} 20 int mymin(int x,int y) {return x<y?x:y;} 21 22 int fa[Maxn]; 23 24 bool vis[Maxn]; 25 int get_lca(int now) 26 { 27 int x=t[now].x,y=t[now].y,ans=0; 28 for(int i=1;i<=n;i++) vis[i]=0; 29 while(x!=fa[x]) vis[x]=1,x=fa[x]; vis[x]=1; 30 while(y!=fa[y]) 31 { 32 if(vis[y]) {ans=y;break;} 33 y=fa[y]; 34 } 35 if(ans==0&&vis[y]) ans=y; 36 // while(x!=fa[x]) vis[x]=0,x=fa[x]; vis[x]=0; 37 return ans; 38 } 39 40 int dis[Maxn],mn,cnt; 41 void ffind(int now) 42 { 43 int x=t[now].x,y=t[now].y; 44 // if(fa[x]!=fa[y]) return; 45 int lca=get_lca(now); 46 if(lca==0) return; 47 int k=INF,kv; 48 while(x!=lca) 49 { 50 if(dis[x]<k) 51 { 52 k=dis[x]; 53 kv=x; 54 } 55 x=fa[x]; 56 } 57 while(y!=lca) 58 { 59 if(dis[y]<k) 60 { 61 k=dis[y]; 62 kv=y; 63 } 64 y=fa[y]; 65 } 66 fa[kv]=kv,dis[kv]=0; 67 mn=INF; 68 for(int i=1;i<=n;i++) if(fa[i]!=i) 69 { 70 mn=mymin(mn,dis[i]); 71 } 72 cnt--; 73 } 74 75 void add(int now) 76 { 77 int x=t[now].x,y=t[now].y,c=t[now].c; 78 if(fa[x]==fa[y]) return; 79 if(fa[x]==x) fa[x]=y,dis[x]=c; 80 else if(fa[y]==y) fa[y]=x,dis[y]=c; 81 else 82 { 83 int xx=x,u=fa[x],dd=dis[x]; 84 while(x!=u) 85 { 86 int nu=fa[u],nd=dis[u]; 87 fa[u]=x; 88 dis[u]=dd; 89 x=u;u=nu;dd=nd; 90 } 91 fa[xx]=y;dis[xx]=c; 92 } 93 mn=mymin(mn,c); 94 cnt++; 95 } 96 97 int main() 98 { 99 while(1) 100 { 101 scanf("%d",&n); 102 if(n==0) break; 103 scanf("%d",&m); 104 for(int i=1;i<=m;i++) 105 { 106 scanf("%d%d%d",&t[i].x,&t[i].y,&t[i].c); 107 t[i].x++;t[i].y++; 108 } 109 sort(t+1,t+1+m,cmp); 110 cnt=0; 111 memset(vis,0,sizeof(vis)); 112 for(int i=1;i<=n;i++) fa[i]=i; 113 mn=INF; 114 memset(dis,0,sizeof(dis)); 115 int ans=INF; 116 for(int i=1;i<=m;i++) 117 { 118 ffind(i); 119 add(i); 120 if(cnt==n-1) ans=mymin(ans,t[i].c-mn); 121 } 122 printf("%d ",ans); 123 } 124 return 0; 125 }
WC这题代码把LA3887 A了!!!!
2016-11-02 09:52:33
--------------------------------------------------------------------------
突然发现这题是删边模版?