【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:
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-苗条树】最大边与最小边差值最小的生成树,并查集的更多相关文章
- Poj 3522 最长边与最短边差值最小的生成树
		
题意: 让你求一颗生成树,使得最长边和最短边长度差值最小. 思路: 额!!!感觉这个思路会超时,但是ac了,暂时没什么别的好思路,那么就先说下这个思路,大牛要是有好的思路希望能在 ...
 - LD1-K(求差值最小的生成树)
		
题目链接 /* *题目大意: *一个简单图,n个点,m条边; *要求一颗生成树,使得其最大边与最小边的差值是所有生成树中最小的,输出最小的那个差值; *算法分析: *枚举最小边,用kruskal求生成 ...
 - 基于visual Studio2013解决面试题之1101差值最小
		
 题目
 - poj3522 苗条树(极差最小生成树)
		
给你N个点和M条边 要求你求出一个生成树使得这个生成树里边权极差最小 做法① n*m做法 当最小的边已知的时候这个生成树就确定 所以最大的边也确定了 于是我们每次枚举最小的边 然后用kruskal做一 ...
 - 传说中的华为Python笔试题——两等长整数序列互换元素,序列和的差值最小(修正)
		
有两个序列a,b,大小都为n,序列元素的值任意整形数,无序:要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小. 1. 将两序列合并为一个序列,并排序,得到source ...
 - P1223 [小数据版]边权差值最小的生成树
		
这道题和最小生成树kruskal的代码几乎相同,只不过不一定是最小生成树,所以不一定从最短的边开始做生成树:所以将每一条边分别作为起点,然后枚举就行了...... #include <bits/ ...
 - find the most comfortable road(并差集,找差值最小的权值)
		
find the most comfortable road Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K ...
 - 将元素平分成差值最小的两个集合(DP)
		
现有若干物品,要分成较为平均的两部分,分的规则是这样的: 1)两部分物品的个数最多只能差一个. 2)每部分物品的权值总和必须要尽可能接近. 现在请你编写一个程序,给定现在有的物品的个数以及每个物品的权 ...
 - LeetCode 530. Minimum Absolute Difference in BST (二叉搜索树中最小绝对差)
		
Given a binary search tree with non-negative values, find the minimum absolute difference between va ...
 
随机推荐
- java多线程三之线程协作与通信实例
			
多线程的难点主要就是多线程通信协作这一块了,前面笔记二中提到了常见的同步方法,这里主要是进行实例学习了,今天总结了一下3个实例: 1.银行存款与提款多线程实现,使用Lock锁和条件Condition. ...
 - 团队第一次作业 ——404 Note Found 团队
			
如果记忆是一个罐头的话,我希望这一罐罐头不会过期----<重庆森林> 404 Note Found Team 如果记忆是一个备忘录的话,别说了,它不会过期----<404 Note ...
 - SQL Server 复制:事务发布(读写分离)
			
一.背景 在复制的运用场景中,事务发布是使用最为广泛的,我遇到这样一个场景:在YangJiaLeClub数据库中有表.存储过程.视图.用户定义函数,需要提供给其它程序读取放入缓存,程序需要比较及时的获 ...
 - lintcode-156-合并区间
			
156-合并区间 给出若干闭合区间,合并所有重叠的部分. 样例 给出的区间列表 => 合并后的区间列表: [ [ [1, 3], [1, 6], [2, 6], => [8, 10], [ ...
 - iOS- 非ARC的项目内存管理细节详解(实战)
			
1.前言 接上文:iOS- 如何将非ARC的项目转换成ARC项目(实战) 2.内存管理时相关的配置 当我们把将非ARC的内存管理都管理好后,发现在做有些操作的时候内存还是在一直的缓慢增加 比如做一个最 ...
 - 钉钉 E应用 打开分享外链
			
钉钉 E应用 打开分享外链 外部链接 https://open-doc.dingtalk.com/microapp/dev https://open-doc.dingtalk.com/microapp ...
 - vs2015常用代码块与自定义代码块
			
常用代码块 代码段名 描 述 #if 该代码段用#if和#endif命令围绕代码 #region 该代码段用#region和#endregion命令围绕代码 ~ 该代码段插入一个析构函数 att ...
 - 【.Net】在C#中判断某个类是否实现了某个接口
			
有时我们需要判断某个类是否实现了某个接口(Interface),比如在使用反射机制(Reflection)来查找特定类型的时候. 简单来说,可以使用Type.IsAssignableFrom方法: t ...
 - BZOJ 1076 奖励关(状压期望DP)
			
当前得分期望=(上一轮得分期望+这一轮得分)/m dp[i,j]:第i轮拿的物品方案为j的最优得分期望 如果我们正着去做,会出现从不合法状态(比如前i个根本无法达到j这种方案),所以从后向前推 如果当 ...
 - 【bzoj2272】[Usaco2011 Feb]Cowlphabet 奶牛文字  dp
			
题目描述 Like all bovines, Farmer John's cows speak the peculiar 'Cow'language. Like so many languages, ...