zoukankan      html  css  js  c++  java
  • 【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
    ",ans);
    119     }
    120     return 0;
    121 }
  • 相关阅读:
    Win10中的IIS10安装php manager和IIS URL Rewrite
    第十四周
    第十三周
    第十二周
    第十一周
    第十周
    第九周
    测试作业
    第八周
    第七周
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/6042341.html
Copyright © 2011-2022 走看看