题意:求最大边与最小边差值最小的生成树。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:

 int find_lca(int x,int y)
{
memset(inx,,sizeof(inx));
memset(iny,,sizeof(iny));
int t=,k=;
while(x) t++,inx[x]=t,x=fa[x];
while(y) k++,iny[y]=k,y=fa[y];
int z=;
for(int i=;i<=n;i++)
{
if(inx[i] && iny[i])
{
if(z==) z=i;
else if(inx[i]<inx[z] || iny[i]<iny[z]) z=i;
}
}
return z;
}

删边:

这道题涉及删边丫。。又要n*m做出来。。

fa[]其实就是一条有向边,其实我们只需要修改fa[]和dis[]就可以了。

我就t0表示那个fa[id]所代表的有向边是要删除的 是在x还是y。

具体看代码把。。注意暴栈(我也不知道为什么),就改成了数组+while。

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std; const int N=,M=*,INF=(int)1e9;
struct node{
int x,y,d,next,bk;
}a[M];
int n,m,t0,t1,id,f[N],fa[N],dis[N],inx[N],iny[N],c[N],p[N]; bool cmp(node x,node y){return x.d<y.d;}
int maxx(int x,int y){return x>y ? x:y;}
int minn(int x,int y){return x<y ? x:y;} int findfa(int x)
{
if(f[x]==x) return f[x];
return findfa(f[x]);
} int find_lca(int x,int y)
{
memset(inx,,sizeof(inx));
memset(iny,,sizeof(iny));
int t=,k=;
while(x) t++,inx[x]=t,x=fa[x];
while(y) k++,iny[y]=k,y=fa[y];
int z=;
for(int i=;i<=n;i++)
{
if(inx[i] && iny[i])
{
if(z==) z=i;
else if(inx[i]<inx[z] || iny[i]<iny[z]) z=i;
}
}
return z;
} void find_min(int x,int y,int z)
{
int mn=INF,xx=x,yy=y;
while(x!=z)
{
if(dis[x]<mn) mn=dis[x],id=x,t0=xx,t1=yy;
x=fa[x];
}
while(y!=z)
{
if(dis[y]<mn) mn=dis[y],id=y,t0=yy,t1=xx;
y=fa[y];
}
} void change(int x,int pre)
{
int pl=;
c[++pl]=x;p[pl]=pre;
while(x && x!=id)
{
c[++pl]=fa[x];p[pl]=x;
x=fa[x];
}
for(int i=pl;i>=;i--)
{
fa[c[i]]=p[i];
dis[c[i]]=dis[p[i]];
}
} int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
while()
{
scanf("%d",&n);
if(!n) return ;
scanf("%d",&m);
memset(fa,,sizeof(fa));
memset(dis,,sizeof(dis));
for(int i=;i<=n;i++) f[i]=i;
for(int i=;i<=m;i++)
{
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].d);
a[i].x++,a[i].y++;
}
sort(a+,a++m,cmp);
int x,y,z,d,mn,cnt=,ans=INF;
for(int i=;i<=m;i++)
{
x=a[i].x,y=a[i].y,d=a[i].d;
if(findfa(x)!=findfa(y))
{
cnt++;
id=;change(x,y);
dis[x]=d;
f[findfa(x)]=findfa(y);
}
else
{
z=find_lca(x,y);
find_min(x,y,z);
change(t0,t1);
dis[t0]=d;
}
if(cnt>=n-)
{
mn=INF;
for(int j=;j<=n;j++)
if(fa[j]) mn=minn(mn,dis[j]);
ans=minn(ans,d-mn);
}
}
printf("%d\n",ans);
}
return ;
}

【poj3522-苗条树】最大边与最小边差值最小的生成树,并查集的更多相关文章

  1. Poj 3522 最长边与最短边差值最小的生成树

    题意:       让你求一颗生成树,使得最长边和最短边长度差值最小. 思路:      额!!!感觉这个思路会超时,但是ac了,暂时没什么别的好思路,那么就先说下这个思路,大牛要是有好的思路希望能在 ...

  2. LD1-K(求差值最小的生成树)

    题目链接 /* *题目大意: *一个简单图,n个点,m条边; *要求一颗生成树,使得其最大边与最小边的差值是所有生成树中最小的,输出最小的那个差值; *算法分析: *枚举最小边,用kruskal求生成 ...

  3. 基于visual Studio2013解决面试题之1101差值最小

     题目

  4. poj3522 苗条树(极差最小生成树)

    给你N个点和M条边 要求你求出一个生成树使得这个生成树里边权极差最小 做法① n*m做法 当最小的边已知的时候这个生成树就确定 所以最大的边也确定了 于是我们每次枚举最小的边 然后用kruskal做一 ...

  5. 传说中的华为Python笔试题——两等长整数序列互换元素,序列和的差值最小(修正)

    有两个序列a,b,大小都为n,序列元素的值任意整形数,无序:要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小. 1. 将两序列合并为一个序列,并排序,得到source ...

  6. P1223 [小数据版]边权差值最小的生成树

    这道题和最小生成树kruskal的代码几乎相同,只不过不一定是最小生成树,所以不一定从最短的边开始做生成树:所以将每一条边分别作为起点,然后枚举就行了...... #include <bits/ ...

  7. find the most comfortable road(并差集,找差值最小的权值)

    find the most comfortable road Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ...

  8. 将元素平分成差值最小的两个集合(DP)

    现有若干物品,要分成较为平均的两部分,分的规则是这样的: 1)两部分物品的个数最多只能差一个. 2)每部分物品的权值总和必须要尽可能接近. 现在请你编写一个程序,给定现在有的物品的个数以及每个物品的权 ...

  9. LeetCode 530. Minimum Absolute Difference in BST (二叉搜索树中最小绝对差)

    Given a binary search tree with non-negative values, find the minimum absolute difference between va ...

随机推荐

  1. 福大软工1816:Alpha(6/10)

    Alpha 冲刺 (6/10) 队名:第三视角 组长博客链接 本次作业链接 团队部分 团队燃尽图 工作情况汇报 张扬(组长) 过去两天完成了哪些任务: 文字/口头描述: 1.组织会议 2.帮助队员解决 ...

  2. 什么是BCL

    原文: 原文:https://www.cnblogs.com/1996V/p/9037603.html 什么是BCL 当你通过VS创建一个项目后,你这个项目就已经引用好了通过.NET下的语言编写好的一 ...

  3. 关于PHP使用GD库生成的验证码无法在别处显示

    https://segmentfault.com/q/1010000002522270

  4. 菜鸟的飞翔日记-os篇

    一轮王道os复习感想 1概述 虽然去年有上操作系统这门必修课,考的成绩也算理想,本来还有点沾沾自喜,嗯,觉得自己学的还不错,知道有一天我拿起了王道,(没给王道打广告)看王道的原因完全在于为考研做准备, ...

  5. apiDoc 入门

    网站 http://apidocjs.com/#demo Install npm install apidoc -g Run apidoc -i myapp/ -o apidoc/ -t mytemp ...

  6. 当重写了 httpservlet重写了GenericServlet的init方法时候 必须显示调用GenericServlet的init方法时候 才能在别的方法(父类创建config实例) 例如 doget里面使用servletContext对象 不重写init 则可以直接使用

  7. 使用getRequestDispatcher跳转后 能获取到request.setAttribute数据 分析

  8. 【bzoj2591】[Usaco 2012 Feb]Nearby Cows 树形dp

    题目描述 Farmer John has noticed that his cows often move between nearby fields. Taking this into accoun ...

  9. JS面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模式)

    什么是面向对象?面向对象是一种思想. 面向对象可以把程序中的关键模块都视为对象, 而模块拥有属性及方法. 这样如果我们把一些属性及方法封装起来,日后使用将非常方便,也可以避免繁琐重复的工作.   工厂 ...

  10. WCF服务的建立以及调用

    WCF对我来说既陌生又熟悉,陌生是因为没怎么接触过,熟悉是听得太多,今天抽出点时间看了一下WCF,并且自己也写了一WCF的小程序以及调用WCF.步骤为: 1.创建一个解决方案WCF,和一个控制台项目W ...