共有回帖数 0 个
-
第一部分:
问题示例:连通性(connectivity)
假如已知一个整数对(pair)序列,其中每个整数代表某种类型的一个对象,而且将p-q对解释成“p与q连通”。
假定关系“与.......”是可传递的:
如果p与q连通,同时q与r连通,则p与r连通.
我们的目的是编写一段程序,从集合(set)中过滤额外连接对;当程序输入一个对p-q,仅当程序此时已经看到的对不能通过可传递性证明p与q连通时,它才输出该对。如果前面的对表明p与q
连通,则程序应该忽略p-q,并继续输入下一个对。如:
3-4 3-4
4-9 4-9
8-0 8-0
2-3 2-3
5-6 5-6
2-9 2-3-4-9
5-9 5-9
7-3 7-3
4-8 4-8
5-6 5-6
0-2 0-8-4-3-2
6-1 6-1
注释
已知一个代表对象间连通性的整数对序列(一楼左边一列)
连通性算法的任务是输出那些提供了新连通的对(中间一列)如:对2-9不在输出列中,
因为前面的连通暗示存在2-3-4-9连通(右边的为推论佐证)
好了,我先吃饭去了
由于算法非常多,内容也非常广泛
所以我只能列举几个
希望大家谅解
今天讲的是:
连通性问题的快速查找解决方案:
#include stdio.h
#define N 10000
main()
{
int i,p,q,t,id[N];
for(i=0;iN;i++)
id=i;
while(scanf("%d %dn",&p,&q)==2)
{
if(id[p]==id[q])continue;
for(t=id[p],i=0;iN;i++)
if(id==t) id=id[q];
printf("%d %dn",p,q);
}
}
这个程序从标准输入读取一个小于N的非负整数对序列(“p q 对”的意思是“连通对象p与对象q”),并且打印表示尚未连通对象的对。该程序使用了一个数组id,其中每项对应一个对象。
它具有以下属性:
仅当p与q 连通时,id[p]与id[q]相等。为了简单起见,我们将N定义成一个编译时常量
(complile--time constant)
另一个办法是:从输入读取它,再动态分配id数组。(具体方法以后在讲)
连通性问题的快速并集解决方案:
如果我们用下面代码替换上面程序中的while循环体,得到的结果是同样的,但并集运算计算量少,查找运算计算量大。代码中的for循环以及后面的if语句定义了p和q连通的id数组的必要且充分条件。
赋值语句id=j实现并集运算,代码如下:
for(i=p;i!=id;i=id);
for(j=q;j!=id[j];j=id[j]);
if(i==j) continue;
id=j;
printf("%d %dn",p,q);
快速并集的加权版本
这个程序是快速并集算法(上一个)的修改版本,
它使用一个额外的数组sz完成维护的目的,
为每个对象用id==i来表示,即在关联树中节点的数量。
因此,并集运算可以连接两棵指定树中的较小者与较大者,以此阻止树中长路径的增长。
#include stdio.h
#define N 10000
main()
{int i,j,p,q,id[N],sz[N];
for(i=0;iN;i++)
{id=i;sz=1;}
while(scanf("%d %dn",&p,&q)==2)
{
for(i=p;i!=id;i=id);
for(j=q;j!=id[j];j=id[j]);
if(i==j) continue;
if(szsz[j])
{id=j;sz[j]+=sz;}
else{id[j]=i;sz+=sz[j];}
printf("%d %dn",p,q);
}
}
最坏的情况:
对于加权快速并集算法最坏的情况是,每个并集运算连接和等大小树。如果对象的数量小于2的n次方,则从任意节点到树根的距离小于n.
对分路径压缩:
如果我们用如下代码替换上一个程序中的for循环,就可以对分我们所遍历的路径长度。
这种变化的最终结果是,经过一个长运算序列后,树变得几乎完全扁平。
for(i=p;i!=id;i=id)
id=id[id];
for(j=q;j!=id[j];j=id[j])
id[j]=id[id[j]];
搜索:
每次不成功搜索,顺序搜索都搜索N个数字,而成功搜索平均搜索约N/2个数字
如果下面的每个数字成为搜索对象的几率相等,则:
(1+2+...+N)/N=(N+1)/2
为搜索的平均开销。
下面我举两个例子一:
顺序搜索:
这个函数检查数V是否在与先前保存的数字集合a[1],a[1+1],...,a[r]中,
方法是从头到尾按顺序比较每个数。
如果搜索到了末尾,而没有找到搜索对象,则返回值-1。否则,返回包含搜索目标的数组位置索引。好了费话说到这里,代码如下:
int search(int a[],int v,int l,int r)
{ int i;
for(i=1;i=r;i++)
if(v==a) return i;
return -1;
}
按最坏的情况考虑,顺序搜索在有序表中每次检查N个数,所有搜索的平均搜索量为N/2个数。
对于不成功搜索仍然需要指定一个模型。假定前提是:在有序表中N个数定义的N+1个区间中,
搜索在每个区间终止的几率均等。因此,立即可以得到下式:
(1+2+...+N+N)/N=(N+3)/2
在表中第N项之前,之后终止的未成功搜索的开销都是相同值:N
二:
二分搜索:
这个程序与上一个功能相同,但效率更高
int search(int a[],int v,int l,int r)
{
while(r=l)
{
int m=(l+r)/2;
if(v==a[m]) return m;
if(va[m]) r=m-1;
else l=m+1;
}
return -1;
}
楼主 2016-03-26 14:20 回复
Copyright © 2010~2015 直线网 版权所有,All Rights Reserved.沪ICP备10039589号
意见反馈 |
关于直线 |
版权声明 |
会员须知