深度优先搜索DFS 模板及模板题

深度优先搜索

深度优先搜索算法(英语:Depth-First-Search,DFS)是一种用于遍历或搜索树或图的算法。沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。
有一点感觉很有趣,因发明“深度优先搜索算法”,约翰·霍普克洛夫特与罗伯特·塔扬在1986年共同获得计算机领域的最高奖:图灵奖。
八皇后问题
经典的dfs入门题

#include<cmath>
#include<cstdio>
#include<cstring> 
#include<algorithm>
using namespace std;
const int maxn=12; 
int map[maxn][maxn];
int ans,n;
int ans_arr[maxn];
void dfs(int ithqueue);
int main()
{
	for(n=1;n<maxn;++n)     		//n代表几皇后 
	{				
		ans=0; 
		for(int i=1;i<=n;++i)
		{
			for(int j=1;j<=n;++j)map[i][j]=0;			
		}
		dfs(1);						//从第一个开始放 
		ans_arr[n]=ans;
	}
	int q;
	while(~scanf("%d",&q),q){
		printf("%d\n",ans_arr[q]);
	}
	return 0;	
}
void dfs(int ithqueue){         	   //ithqueue代表当前放了第几个 
	if(ithqueue==n+1){				   //如果放到了第n+1个,代表放完了。 
		ans++;
		return ;
	}
	for(int col=1;col<=n;++col)                 //很明显第几个皇后代表第几行,col从1到n开始扫描,代表将当下的皇后放到第几列 
	{				
		if(map[ithqueue][col]==0)			    //等于0,代表可以放 
		{
			for(int i=1;i<=n;++i)				//如果该行该列该斜线还是0的话则标记 
			{			
				for(int j=1;j<=n;++j)
				{
					if(( i==ithqueue || col==j ||  abs(i-ithqueue)==abs(col-j) ) && map[i][j]==0)
					{
						map[i][j]=ithqueue;
					} 
				}
			} 
			dfs(ithqueue+1);					//放下一个皇后 
			
			for(int i=1;i<=n;++i)				//回溯 
			{
				for(int j=1;j<=n;++j)
				{
					if(map[i][j]==ithqueue) map[i][j]=0;
				}
			}	
		}	
	}
}

质数环问题
通过深搜实现全排列1

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath> 
#include<queue> 
using namespace std;
//queue<int> a;					//本来想开队列保存答案,感觉这样会超时
int arr[21]; 					//用来标记是否已经放过改数字 
int cir[21];					//保存答案 
int num,h,flag,T=1;
void dfs(int n);
int isPrime(int n);

int main()
{
	while(~scanf("%d",&num))
	{
	    for(int i=0;i<20;i++) arr[i]=1;
		flag=1;
	   	cir[1]=1;				//将1先置于环内
		arr[1]=0;				//1已经用过了 
		dfs(2); 				//放第二个数	
		printf("\n");
	}
	return 0;
}

void dfs(int n){
	if(flag)
	{
		printf("Case %d:\n",T);
		flag=0;
		T++;		
	}
	
	if(n==num+1)
	{                //放满了,退出 
	   if(isPrime(1+cir[num]))
	   {
	   		for(int i=1;i<num;++i)
			{
				printf("%d ",cir[i]);
			}
		 	printf("%d\n",cir[num]);
	   }      
		return ;
	}
	int i;
	for(i=2;i<=num;i++)			//一遍一遍的扫描下一个要放置的数。
	{ 
		if(arr[i]==1 && isPrime(i+cir[n-1]) )//如果这个数没有被放过,并且这个数和之前放进的数相加等于质数,则放进该数。
		{	
			arr[i]=0;			//这个数已经用过 
			h=i;
			cir[n]=i;			//将i这个数放进环里 
			dfs(n+1);			//开始放置下一个数 
			arr[i]=1;			//回溯 
		}
	}
	if(i==num+1) return ;		//后面的数怎么放都不行了,结束。 
}
int isPrime(int n)				
{
	int i,k;
	k=sqrt(n);
	for(i=2;i<=k;i++)
	{
		if(n%i==0) break;
	}
	if(i<=k) return 0;
	else return 1;
}

网易:最小众倍数
通过深搜实现全排列2

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int num[5];
int vis[5];
int stc[3];
int top;
int maxn=1<<30;
int ans;
int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}
int lcm(int a,int b,int c)
{
    int lcm1=a*b/gcd(a,b);
    int lcm2=lcm1*c/gcd(lcm1,c);
    return lcm2;
}
int dfs(int ith)
{
    if(ith==4)
    {
        //cout<<stc[0]<<" "<<stc[1]<<" "<<stc[2]<<endl;
        //cout<<lcm(stc[0],stc[1],stc[2])<<endl;
        if(lcm(stc[0],stc[1],stc[2])<ans)
        {
            ans=lcm(stc[0],stc[1],stc[2]);
        }
        return 0;
    }
    for(int i=0;i<5;++i)
    {
        if(!vis[i])
        {
            vis[i]=1;
            stc[top++]=num[i];
            dfs(ith+1);
            vis[i]=0;
            top--;
        }
    }
    return 0;
}
int main()
{
    while(cin>>num[0]>>num[1]>>num[2]>>num[3]>>num[4])
    {
        memset(vis,0,sizeof(vis));
        top=0;
        ans=maxn;
        dfs(1);
        cout<<ans<<endl;
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章