DFSディープ最適化検索

DFSディープ最適化検索

DFSアルゴリズム

考え:解決策が見つかるか、続行できなくなるまで、深く掘り下げていきます

これは、ツリーの最初のルートトラバースに似ています。南の壁にぶつかったり、振り返ったりしないでください

模板一:
DFS(dep,..)//dep代表目前DFS的深度
{
	if(找到解||走不下去)
	{
		...
		return;
	}
	DFS(dep+1,..)//枚举下一种情况
}

模板二:
DFS(dep,..)
{	
	if(判断条件)
	return;
	for(扩展转态)
	{
		判断合法;
		记录;
		DFS(dep+1,...)
		回溯;
	}
}

DFSトラバーサルグラフ

1.図のv0から始めて、v0にアクセスします。

2. v0の最初の未訪問の隣接ポイントを見つけて、頂点にアクセスします。この頂点を新しい頂点として、アクセスしたばかりの頂点に未アクセスの隣接ポイントがなくなるまで、この手順を繰り返します。

3.まだ訪問されていない隣接ポイントがある以前に訪問された頂点に戻り、この頂点の次の訪問されていない先行ノードに引き続き訪問します。

4.すべての頂点にアクセスして検索が終了するまで、手順2と3を繰り返します。

v0-> v2-> v4-> v6-> v1-> v5-> v3

v0
v2
v1
v3
v4
v5
v6

DFS質問タイプ


1つ:データタイプ

素環の問題

題名

数値nが与えられた場合、数値1〜nを円で囲みます。要件:2つの隣接する数値の合計が素数です。

0 <n <20

出力:

  • 数字の方向は同じ(同じ時計回りまたは同じ反時計回り)であり、配置は繰り返されません
  • 数値が1つしかない場合(n == 1)、出力1
  • 出力ケースk:(kはデータグループの数)、出力の各グループ(最初のグループを除く)の前に空白行があります

アイデア

各再帰の前に、最初の2つの数値の合計が素数であるかどうかを判断します。これはリングであるため、最後の数値と最初の数値も満たす必要があるためです。

DFSの前は、素数を使用してふるいにかけ、50以内の素数を見つけることができます。ここで、nは20であり、最大の2つの素数の合計は50未満です。

コード

#include<bits/stdc++.h> 
using namespace std;
const int MAX=50;
int prime[25];//素数数组 
bool vis[25]; //访问数组 
int n;// 个数 
int ans[MAX];//解答输出数组 
void Prime_set()  //筛法求素数 
{
    //Isprime 0、 IsNotprime 1  
    for(int i = 2; i<=sqrt(MAX) ;++ i)
        if(prime[i] == 0)
		{
            for(int j = 2;i*j<=MAX;++j)
                prime[i*j] = 1;
        }
    prime[1] = 0,vis[1]=true;//1虽然不是素数,但在此假设为0,将vis[1]设为true即不会遍历到1 
}
void DFS(int depth)
{
    if(prime[ans[depth-1]+ans[depth-2]]!=0) return ;  //前两个数之和不是素数退出 
    if(depth==n+1&&prime[ans[depth-1]+ans[1]]!=0) return ; //当选到最后一个数时,第一个数和最后一个数之和不是素数时退出 

    if(depth==n+1)  //选到最后一个数,输出 
    {
        for(int i=1;i<=n;i++) 
        {
            if(i==1) cout<<ans[i]; 
            else cout<<" "<<ans[i]; 
        }
            cout<<endl;
    }

    for(int i=2;i<=n;i++)   //把1~n按照一定顺序(DFS求得)填入数组ans 
    {
        if(!vis[i]) 
        {
            vis[i]=true;
            ans[depth]=i;
            DFS(depth+1);
            vis[i]=false;
        }
    }
}
int main(){
    int t=1; 
    Prime_set();
    while(cin>>n)
    {
        cout<<"Case "<<t++<<":"<<endl;
        memset(vis,false,sizeof(vis));
        memset(ans,0,sizeof(ans));
        ans[1] = 1;//1永远是首元素 
        if(n==1) cout<<"1"<<endl;
        else 
            DFS(2);//1永远是首元素,从2开始DFS ;也防止之后depth-2<0 
        cout<<endl;
    }   
    return 0;
}

タイトルの説明:番号を選択してください

既知のn個の整数x1、x2、...、xn x_n x ** nおよび1個の整数k(k <n)。n個の整数から、オプションでk個の整数を加算して、それぞれ一連の合計を取得します。たとえば、n = 4、k = 3、および4つの整数が3、7、12、19の場合、すべての組み合わせとそれらの合計は次のようになります。

3 + 7 + 12 = 22

3 + 7 + 19 = 29

7 + 12 + 19 = 38

3 + 12 + 19 = 34

ここで、何種類の合計が素数であるかを計算する必要があります。

たとえば、上記の例では、1種類の合計のみが素数です:3 + 7 + 19 = 29

#include<bits/stdc++.h>
using namespace std;
int a[10005],sum=0,ans=0;
int n,k;
int sushu(int f)
{
	for(int i=2;i*i<=f;i++)
	{
		if(f%i==0)
		return 0;
	}
	return 1;	
} 
void dfs(int x,int y)//x表示差几个数,y表示选到a[y] 
{
	if(x==0)
	ans+=sushu(sum);
	else
	{
		y++;
		for(int i=y;i<=n;i++)
		{
			sum+=a[i];
			x--;
			dfs(x,i);
			sum-=a[i];//回溯 
			++x;
		}
	}
}  
int main()
{
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	dfs(k,0);
	cout<<ans<<endl;
	getchar();
    getchar();
    return 0;
}

2:グラフィック

マトリックス内のパス

文字列のすべての文字を含むパスがマトリックスにあるかどうかを判断する関数を設計してください。

パスはマトリックス内の任意のグリッドから開始でき、各ステップで1つのグリッドをマトリックス内で左、右、上、下に移動できます。

パスがマトリックス内の特定のグリッドを通過する場合、後でこのグリッドに再び入ることはできません。

注意:

  • 入力されたパスは空ではありません。
  • 表示される文字はすべて大文字の英字です

サンプル

matrix=
[
  ["A","B","C","E"],
  ["S","F","C","S"],
  ["A","D","E","E"]
]

str="BCCE" , return "true" 

str="ASAE" , return "false"

コード:

class Solution {
public:
    bool hasPath(vector<vector<char>>& matrix, string &str) 
    {
        for(int i=0;i<matrix.size();i++)
        {
            for(int j=0;j<matrix[i].size();j++)
            {
                if(dfs(matrix,str,0,i,j))//对每一个点深搜,起点不一样
                return true;
            }
        }
        return false;
    }
    
    bool dfs (vector<vector<char>>& matrix,string &str,int u,int i,int j )
    {
        if(matrix[i][j]!=str[u])return false;//不满足
        if(u==str.size()-1)return true;//找到了一条路径满足
        char t=matrix[i][j];//回溯需要
        matrix[i][j]='*';
        int dx[4]={0,0,-1,1},dy[4]={1,-1,0,0};//方向向量
        for(int m=0;m<4;m++)
        {
            int a=i+dx[m],b=j+dy[m];
            if (a >= 0 && a < matrix.size() && b >= 0 && b < matrix[a].size()) 
           {
                if(dfs(matrix,str,u+1,a,b))
            return true;
           }
        }
        matrix[i][j]=t;//回溯
        return false;
        
    }
    
};

迷路から

Xiao Mingは現在ゲームをプレイしており、迷路はN * Mマトリックスです。

Xiao Mingの始点はマップ上で「S」で表され、終点は「E」で表され、障害物は「#」で表され、オープンスペースは「。」で表されます。

障害物は通過できません。Xiao Mingがポイント(x、y)にある場合、次のステップは4つの隣接するグリッド((x + 1、y)、(x-1、y)、(x、y)のいずれかにのみ進むことができます。 +1)、(x、y-1);

シャオミンは今、最初から最後まで歩くことができるかどうか知りたがっています

サンプル入力
3 3
S..
..E
...
3 3
S##
###
##E
サンプル出力
Yes
No

ACコード

#include<bits/stdc++.h>
using namespace std;
int n,m,flag=0,a,b;//flag是标记能否到达 
const int MAX=510;
char s[MAX][MAX];
int dx[]={-1, 1, 0, 0}, dy[]={0, 0, -1, 1};//方向向量 

void DFS(int i,int j)
{
	if(flag||s[i][j]=='#'||i<0||i>=n||j<0||j>=m)//判出 
	return;
	if(s[i][j]=='E')//到达终点 
	{
		flag=1;
		return;
	}
	s[i][j]='#';//走过了的路不回头 
	for(int e=0; e<4; e++)
    	DFS(i+dx[e], j+dy[e]);//继续深搜 
}

int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		flag=0;//每一组数据重新赋值为0 
		for(int i=0;i<n;i++)
		scanf("%s",s[i]);
			for(int i=0;i<n;i++)
				for(int j=0;j<m;j++)
					if(s[i][j]=='S')a=i,b=j;//起点标记 
		DFS(a,b);
		if(flag)
		 puts("Yes");
		else
		puts("No");
	}
	return 0;
}

おすすめ

転載: blog.csdn.net/qq_46029533/article/details/109378863