深度優先搜索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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章