【Uvalive4960】 Sensor network (苗条树,进化版)

【题意】

  给出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\n",ans);
123     }
124     return 0; 
125 }
View Code

 

WC这题代码把LA3887 A了!!!!

 

2016-11-02 09:52:33

 

--------------------------------------------------------------------------

突然发现这题是删边模版?

posted @ 2016-11-02 09:48  konjak魔芋  阅读(231)  评论(0编辑  收藏  举报