• 【算法】深度优先搜索(DFS)III


    1. DFS生成排列


    众所周知,1,2…n的排列一共有n!个,因此生成全排列至少需要n!的时间复杂度。如果用循环来生成排列,当n稍大时,内外循环会非常之多。可以用DFS模拟解决,生成0 … n-1的排列的代码如下:

    void dfs(int depth)
    {
    	int i,length;
    	if(depth==n)                 //n个数排列完毕
    	{
    		print the result
    		return;
    	}
    
    	for(i=0;i<n;i++)
    		if(!visit[i])           //点i没被访问
    		{
    			visit[i]=1;
    			result[depth]=i;
    			dfs(depth+1);       //进入下一次递归
    			visit[i]=0;         //回溯,将点i重新标记为未被访问
    		}
    }


    2. 问题


    2.1 POJ 2907


    题目大意:从start点出发,经过n个beeper点后,回到start点;求最短路径。


    思路:由于n<=10,可以用全排列解决。将n个beeper点排列,所得的序列即为经过beeper点的先后顺序,然后计算路径长度。在这n!个路径中,找出最小值。


    源代码:

    2907 Accepted 164K 0MS C 1127B 2013-10-10 21:16:22
    #include "stdio.h"
    #include "stdlib.h"
    #include "string.h"
    #include "limits.h"
    
    typedef struct position
    {
    	int x,y;
    }Position;
    
    int n,minimum,result[10],visit[10];
    Position start,beeper[10];
    
    int distance(Position a,Position b)
    {
    	return abs(a.x-b.x)+abs(a.y-b.y);
    }
    
    void dfs(int depth)
    {
    	int i,length;
    	if(depth==n)
    	{
    		length=0;
    		for(i=1;i<n;i++)
    			length+=distance(beeper[result[i]],beeper[result[i-1]]);
    		length+=distance(beeper[result[0]],start);
    		length+=distance(beeper[result[n-1]],start);
    		if(length<minimum)
    			minimum=length;
    		return;
    	}
    
    	for(i=0;i<n;i++)
    		if(!visit[i])
    		{
    			visit[i]=1;
    			result[depth]=i;
    			dfs(depth+1);
    			visit[i]=0;
    		}
    }
    
    int main()
    {
    	int scenarios,xsize,ysize,i;
    	scanf("%d",&scenarios);
    	while(scenarios--)
    	{
    		scanf("%d%d",&xsize,&ysize);
    		scanf("%d%d%d",&start.x,&start.y,&n);
    		for(i=0;i<n;i++)
    			scanf("%d%d",&beeper[i].x,&beeper[i].y);
    
    		memset(visit,0,sizeof(visit));
    		minimum=INT_MAX;
    		dfs(0);
    		printf("The shortest path has length %d
    ",minimum);
    
    	}
    	return 0;
    }


    2.2 POJ 1256


    题目大意:有n个字母word,可能含有重复元素,求其全排列。


    在DFS生成排列时,会碰到重复元素,为了不重复输出同一个排列,需要进行剪枝。扫描到当前字母i与其前一个字母i-1相同,且字母i-1未被访问,则选择跳过。


    少写了一句结束标志 result[depth]='';   WA了N久。分析:因为result会记录上一个word的排列,所以会对下一个word产生影响;比如,输入abc和ab,等到输出ab的排列时,会输出cba的结果。


    源代码:

    1256 Accepted 156K 32MS C 825B 2013-10-11 15:27:01
    #include "stdio.h"
    #include "stdlib.h"
    #include "string.h"
    #include "ctype.h"
    
    int n,visit[13];
    char word[13],result[13];
    
    int cmp(const void *a,const void *b)
    {
    	char c=*(char *)a,d=*(char *)b;
    	return tolower(c)==tolower(d)?c-d:tolower(c)-tolower(d);
    }
    
    void dfs(int depth)
    {
    	int i;
    	if(depth==n)                 
    	{
    		result[depth]='';                        //少写了这一句,WA了N久
    		puts(result);
    		return;
    	}
    
    	for(i=0;i<n;i++)
    	{
    		if(i>0&&word[i]==word[i-1]&&!visit[i-1])   //剪枝:如果当前字母i与其前一个字母i-1相同,且字母i-1未被访问,则跳过
    			continue;
    		if(!visit[i])           
    		{
    			visit[i]=1;
    			result[depth]=word[i];
    			dfs(depth+1);       
    			visit[i]=0;
    		}
    	}
    }
    
    int main()
    {
    	int num_word;
    	scanf("%d",&num_word);
    	while(num_word--)
    	{
    		scanf("%s",word);
    		n=strlen(word);
    		qsort(word,n,sizeof(char),cmp);
    		memset(visit,0,sizeof(visit));
    		dfs(0);
    	}
    	return 0;
    }





  • 相关阅读:
    Rainmeter 雨滴桌面 主题分享
    行人检測之HOG特征(Histograms of Oriented Gradients)
    const和readonly差别
    ADB命令解析
    Java实现 蓝桥杯VIP 算法训练 接水问题
    Java实现 蓝桥杯VIP 算法训练 星际交流
    Java实现 蓝桥杯VIP 算法训练 星际交流
    Java实现 蓝桥杯VIP 算法训练 星际交流
    Java实现 蓝桥杯VIP 算法训练 星际交流
    Java实现 蓝桥杯VIP 算法训练 星际交流
  • 原文地址:https://www.cnblogs.com/fuhaots2009/p/3363671.html
Copyright © 2020-2023  润新知