您的位置:首页 > 其它

关于深搜和广搜在图中两点间是否存在路径问题上的工作效率情况探讨~

2011-04-13 23:23 288 查看
问题来源:



前两天做了一道图论的ACM题目,其中包含搜索两点之间是否连通

这样一个子问题,当初做的时候用的是STACK实现的深度优先搜索,

然后拿给朋友看时,她竟然来了句太神奇了,你竟然用深搜,怎么不用

广搜呢?



也许效率更高呢!



好吧,当时对深搜和广搜的效率没有探究过,然后听从朋友的意见改成

了广搜一试,结果竟然TLE了...好吧,我承认自己在做那一题时用的算

法相当差劲,即使通过了也花费了860MS的时间,可是同样的搜索,换

成广搜就超时了,当时觉得不可思议,因为从理论上说,两种搜索算法在

时间上的效率是一样的.



然后忽然就回忆起那么一小段话:"在判断是否存在路径问题上,深度优

先搜索速度是高于广度优先搜索的",然后去网上查了查,找不到关于这

个问题的详细解答...在告诉另一个同学LC这个思想的时候,他竟然上来

就说了句"Mao~",呃~



好吧,争吵是不对的,但对问题的探求精神还是值得继续的,趁此机会验

证一下,上面这个想法是否在实践上值得考虑.





问题模型:





给出一无向无权图,判断要求的两点之间是否连通.



输入:

n,m分别代表顶点数和边数

接下来有m行,每行一对整数u,v,表示

点u,v之间有一条边;

接下来一个整数q,表示有q组查询;

每组查询两个整数,f,t表示从f到t的搜索;



输入样例:

5 5

1 3

1 5

2 5

2 4

3 2

3

1 2

3 4

1 4



这个简单的问题模型可以用来简单验证DFS和BFS的效率问题,简单,

所以实效、清晰,嘿嘿~





实践思路:



写出该问题模型的主框架,用于接受输入,及时间统计,其中,图的存储用到邻

接表.有一个AddEdge()函数增加边,然后分别写出几个实现搜索算法的函

数,其中Dfs()为递归实现的深搜,Dfsstk()为栈实现的深搜,Bfs()为广搜.



好吧,写好算法的实现,数据的生成就需要另外写程序解决了,最简单的就是

用随机函数了,这个就不多说啦~待会儿看程序.



实现过程:





未使用STL 提供的queue和stack

偿试递归深搜和栈深搜

用队列实现广搜

用邻接表存储图



好吧,程序写好了,下面就要写另外的程序来生成这些数据了



生成数据之后测试时发现,同样的数据,分别多次进行运算之后,

进行的运算时间消耗竟然相差很多,可能由于进程交替、运行环

境不稳定等原因造成的,所以,对于每组样例,都进行了20次执行,

来得到其总运行时间,这样可以消去一些偶然原因造成的不均衡

结果.





好吧,至此,终于差不多完成了~





首先看一下运行的统计结果:

(每类数据100组,

n个顶点,

n*log(n)*0.5条边,

n*log(n)*0.5次查询

(20次执行总耗时))



WinXP CPU:AMD Athlon(tm)II X2 215 Processor





关于深搜和广搜在图两点间是否连通的判断问题中的统计对比(单位:ms)















n
10
50
100
200
500
1000
DFS
0
77
992
3470
32529
150396
BFS
15
200
2061
7606
90476
385236
DFSSTK
15
61
1078
051
57552
250355
代码如下:

算法代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#define N 10005
#define M 200005
#define DSIZE 10000
typedef struct talNode{
	int v;
	talNode *next;
}Edge;
Edge MEM[M];
int stk[DSIZE],que[DSIZE];
int top,front,tail;
Edge *head
;//邻接表头
bool vis
;
int n,m,e;
int q,f,t;
int total1,total2,total3;
//不使用memcpy();不使用queue和stl;偿试递归深搜和栈深搜
//用队列实现广搜/
void Init()
{
	int i;
	for(i=0;i<=n;i++)
		head[i]=NULL;
	e=0;
}
void AddEdge(int u,int v)
{
	MEM[e].v=v;MEM[e].next=head[u];
	head[u]=&MEM[e++];
	MEM[e].v=u;MEM[e].next=head[v];
	head[v]=&MEM[e++];
}
bool Dfs(int u)
{//深搜,递归实现
	Edge *tmp;
	int v;
	vis[u]=true;
	if(u==t) return true;
	for(tmp=head[u];tmp;tmp=tmp->next){
		v=tmp->v;
		if(vis[v]) continue;
		if(Dfs(v)) return true;
	}
	return false;
}
void DfsStk()
{//深搜,栈实现
	Edge *tmp;
	int u,v;
	top=0;
	vis[f]=true;
	stk[top++]=f;
	while(top){
		u=stk[--top];
		if(u==t) return ;
		for(tmp=head[u];tmp;tmp=tmp->next){
			v=tmp->v;
			if(vis[v]) continue;
			vis[v]=true;
			stk[top++]=v;
		}
	}
}
void Bfs()
{//广搜,队列实现
	Edge *tmp;
	int u,v;
	front=tail=0;
	vis[f]=true;
	que[tail++]=f;
	while(front!=tail){
		u=que[front++];
		front%=DSIZE;
		if(u==t) return ;
		for(tmp=head[u];tmp;tmp=tmp->next){
			v=tmp->v;
			if(vis[v]) continue;
			vis[v]=true;
			que[tail++]=v;
			tail%=DSIZE;
		}
	}
}
void VisInit()
{
	int i;
	for(i=0;i<=n;i++)
		vis[i]=false;
}
void Work1()
{//递归深搜求解,并记录运行时间
	int curt;
	VisInit();
	curt=clock();
	Dfs(f);
	total1+=clock()-curt;
	//printf("Work1:");
	//puts(vis[t]?"YES":"NO");
}
void Work2()
{//广搜求解,并记录运行时间
	int curt;
	VisInit();
	curt=clock();
	Bfs();
	
	total2+=clock()-curt;
	//printf("Work2:");
	//puts(vis[t]?"YES":"NO");
}
void Work3()
{//栈深搜求解,并记录运行时间
	int curt;
	VisInit();
	curt=clock();
	DfsStk();
	
	total3+=clock()-curt;
	//printf("Work3:");
	//puts(vis[t]?"YES":"NO");
}
int main()
{
	int i,u,v;
	freopen("data//data1000.in","r",stdin);
	//freopen("ans//ans.out","w",stdout);
	//初始化运行时间
	total1=total2=total3=0;
	while(scanf("%d%d",&n,&m)!=EOF){
		Init();
		for(i=0;i<m;i++){
			scanf("%d%d",&u,&v);
			AddEdge(u,v);
		}
		scanf("%d",&q);
		while(q--){
			scanf("%d%d",&f,&t);
			Work1();
			Work2();
			Work3();
		}
	
	}
	printf("   DFS:%10d/n",total1);
	printf("   BFS:%10d/n",total2);
	printf("DFSSTK:%10d/n",total3);
	return 0;
}




数据生成代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include<math.h>
#define N 2005
#define M 100005
#define NUM 100
bool map

;
int main()
{//随机生成指定顶点个数规模的测试数据
	int cases=NUM;
	int n,m,u,v,q;
	freopen("data//data1000.in","w",stdout);
	while(cases--){
		memset(map,0,sizeof(map));
		n=1000;
		m=n*(int)(log(n)*0.5);
		printf("%d %d/n",n,m);
		while(m--){
			do{
				u=rand()%n;
				v=rand()%n;
			}while(u==v||map[u][v]);
			map[u][v]=map[v][u]=true;
			printf("%d %d/n",u,v);
		}
		q=n*(int)(log(n)*0.5);
		printf("%d/n",q);
		while(q--){
			do{
				u=rand()%n;
				v=rand()%n;
			}while(u==v);
			printf("%d %d/n",u,v);
		}
		puts("");
	}
	return 0;
}






总结:就好像快排的一般效率是高于堆排一样,此处给我们以关于深搜和广搜更深层次

上的认知,嗯,在以后用到相关算法时,这些数据也能给我们以启示吧.



另:感谢LC同学帮助记录统计的数据~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: