DFS入门学习

博主学习DFS入门后,汇总做过的题目并分享。涉及计蒜客、Codeup、HDU等平台的题目,如全排列、素数个数、补全等式、n皇后问题、激光样式、走迷宫等,还介绍了不同题目的解法,如DFS结合判断、剪枝、打表等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学习DFS看了很多篇博客慢慢入门,感谢我看过的所有博客,我把其中做过的题目汇总起来,里面有很多是大神的代码,与大家分享。

计蒜客A1601全排列

计蒜客A1601全排列
找的是全排列中,排列结果互不相同的个数

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e3;
char str[N], buf[N];//buffer
int vis[N], total, len;
void arrange(int num) {
    if (num == len){
        printf("%s\n", buf);
        total++;
        return;
    }
	for (int i = 0; i < len; ++i) {
        if (!vis[i]) {
            int j;
            for (j = i + 1; j < len; ++j) {
                if (vis[j]&&str[i] == str[j]) {
                    break;
                }
            }
            if (j == len) {
                vis[i] = 1;
                buf[num] = str[i];
                arrange(num + 1);
                vis[i] = 0;
            }
        }
    }
}
int main() {
    while (~scanf("%s",str)) {
        len = strlen(str);
        sort(str, str + len);
        total = 0;
        buf[len] = '\0';
        arrange(0);
        printf("Total %d\n", total);
    }
    return 0;
}

计蒜客A1636素数个数

计蒜客A1636素数个数
题目大致是求0~7的全排列组成的数字(首位不为0)中素数的个数,该题可理解为在全排列的基础上进行了条件限制

  1. DFS+判断 答案:2668
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
typedef unsigned long long ll;
int isPrime1(ll s)
{
	if(s==2||s==3)
		return 1;
	if(s%6!=1&&s%6!=5)
		return 0;
	int t = sqrt(s);
	for(int i=5;i<=t;i++)
	{
		if(s%i==0||s%(i+2)==0)
			return 0;
	}
	return 1;
}
int isPrime2(ll s)
{
	for(int i=2;i*i<=s;i++)
		{
			if(s%i==0) return 0 ;
		}
	return 1;
}
int a[8]= {0};
int vis[8] ={false};
int n;
int cnt;
void dfs(int x)
{
	if(x == n)
	{
		int s = 0;
		for(int i=0;i<n;i++)
			s += (a[i]*pow(10,x-1-i));
		if(isPrime1(s))
		{
			//cout << s << endl;
			cnt++;
		}
		return ;
	}
	for(int i=0;i<n;i++)
	{
		if(i==0&&a[i]==0)
			continue;
		if(vis[i] ==false)
		{
			a[x] = i;
			vis[i] = true;
			dfs(x+1);
			vis[i] = false;
		} 
	}
}
int main()
{
    //cin >> n;
    n = 8;
    cnt = 0;
    dfs(0); //从0开始搜
    cout << cnt;
	return 0;
}

2.调用现成的排列函数next_permutation(a,a+8)
P.S:其实一开始把它给忘了,一直在想怎末用DFS来实现\捂脸=_=,记得这个函数如果n较大会很耗时间,但是用这个函数可以减少代码量,刚好这个题是填空题

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef unsigned long long ll;
int isPrime1(ll s)
{
	if(s==2||s==3)
		return 1;
	if(s%6!=1&&s%6!=5)
		return 0;
	int t = sqrt(s);
	for(int i=5;i<=t;i++)
	{
		if(s%i==0||s%(i+2)==0)
			return 0;
	}
	return 1;
}
int isPrime2(ll s)
{
	for(int i=2;i*i<=s;i++)
		{
			if(s%i==0) return 0 ;
		}
	return 1;
}
int a[8];
int main()
{
   int t=0;
	int a[8]={0,1,2,3,4,5,6,7};
	do{
		if(a[0]==0)
		  continue;
		else
		  {
		    int b=0;
		    b=a[0]*10000000+a[1]*1000000+a[2]*100000+a[3]*10000+a[4]*1000+a[5]*100+a[6]*10+a[7]*1;
          	if(isPrime1(b))
                t++;
		  }
	  }while(next_permutation(a,a+8));//C++中的全排列函数 
	cout<<t;
	return 0;
}

计蒜客A1146补全等式

计蒜客A1146补全等式
1.暴力解法:全排列+判断 时间稍长预计需要172.4s 答案:122368

//
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
    int a[13];
    for(int i=0;i<13;i++)
    {
    	a[i] = i+1;
	}
	int cnt =0;
	do{
		if(a[0]*a[1]+a[2]*a[3] == a[4]*a[5]&&
		a[6]*a[7]-a[8]*a[9] == a[10]*a[11])
		cnt ++;
	}while(next_permutation(a,a+13));
	cout << cnt;
    return 0;
}
  1. DFS+剪枝 0.88s

#include <algorithm>
#include <iostream>
#include <string.h>
using namespace std;
int vis[15], a[15];
int ans;
void dfs(int cur) 
{
    if(cur == 6) 
	{
        if(a[0]*a[1] + a[2]*a[3] != a[4]*a[5]) return;
    }
    if(cur == 12) {
        if(a[6]*a[7] + a[8]*a[9] == a[10]*a[11]) ans++;
        return;
    }
    for(int i = 1; i <= 13; ++i) {
        if(!vis[i]) {
            vis[i] = 1;
            a[cur] = i;
            dfs(cur+1);
            vis[i] = 0;
        }
    }
}

int main() {
    ans = 0;
    memset(vis, 0, sizeof(vis));
    dfs(0);
    cout << ans;
    return 0;
}

Codeup5974: 【递归入门】组合+判断素数

Codeup5974: 【递归入门】组合+判断素数

#include<iostream>
#include<string.h>
using namespace std;
typedef long long ll;
int a[21] = {0};
int num,k,n;
ll sum;
int isPrime(int s)
{
	for(int i=2;i*i<=s;i++)
	{
		if(s%i==0) return 0;
	}
	return 1;
}
void dfs(int index, int x, ll sum)
{
	if(x == k){
		if(isPrime(sum)) num++; 
		return ;
	}
	if(index == n+1) return ;  
	dfs(index+1, x+1, sum+a[index]); //index 数组a的下标 x为已选个数
	dfs(index+1, x, sum);
}
int main()
{	
	num = 0;
	cin >> n >> k;
	for(int i=1;i<=n;i++)
		cin >> a[i];
	dfs(1,0,0);
	cout << num;
	return 0;
}

实现全排列(可单调递增)

#include<iostream>
#include<string.h>
using namespace std;
int p[10]= {0};
bool vis[10] = {false};
int n;
void dfs(int x)
{
	if(x == n+1)
	{
		for(int i=1;i<=n;i++)
			cout << p[i] << " ";
		cout << endl;
	}
	for(int i=1;i<=n;i++)
	{
		//if(vis[i]==false)
		if(vis[i]==false&&i>p[x-1]) /*如若实现单调递增的全排列 */ 
		{
			p[x] = i;
			vis[i] = true;
			dfs(x+1);
			vis[i] = false;
		}
	}
}
int main()
{
	while(cin >> n)
	{
		dfs(1);
		memset(p,0,sizeof(p));
		memset(vis,false,sizeof(vis));
	}
	
	return 0;
}

1~n求所有可能的出栈序列(序列个数)

首先先考虑序列个数有两种解法
1.卡特兰树 ( n 2 n ) \tbinom{n}{2n} (2nn)/(n+1)

#include<iostream>
#include<string.h>
using namespace std;
int n;
int fun(int n) //当然这里n不能过大,过大的话会爆,需要另当别论
{
	int s = 1;
	for(int i=2*n,j=1;i>=n+1,j<=n;i--,j++)
	{
		s = s*i/j;
	}
	return s;
}
int main()
{
	cin >> n;
	cout << fun(n)/(n+1);
	return 0;
}

2.DFS思想,用三个变量,num表示栈内元素个数,假如想进栈出栈n个元素对应的需要进栈n次出栈n次,用push表示所需进栈次数,pop表示所需出栈次数

#include<iostream>
#include<string.h>
using namespace std;
int n;
int p[10]={0};
bool vis[10] = {false};
int count;
void dfs(int num, int pop, int push)
{
	if(pop==0&&push==0)
	{
		count++;
		return ;
	}
	if(push>0)
		dfs(num+1,pop,push-1);
	if(pop>0&&num>0)
		dfs(num-1,pop-1,push);
}
int main()
{
	cin >> n;
	count = 0;
	dfs(0,n,n);
	cout << count;
	return 0;
}

【递归入门】n皇后 问题(原始的8皇后问题)

【递归入门】n皇后 问题(原始的8皇后问题)

#include<iostream>
#include<cmath>
using namespace std;
const int maxn = 25;
int c = 0,Data[maxn] = {0};//c代表解的个数
bool hashTable[maxn] = {0};

void dfs(int n, int k) // 在n行n列的棋盘上在第k行放置皇后,进行尝试 
{
	if(k > n)
	{
		for(int i=1;i<=n;i++)
		{
			cout << Data[i];
			if(i<n) cout << " ";
		}	
		cout << endl;
		c++;
	} 
	for(int i=1;i<=n;i++)
	{
		if(hashTable[i] == false)
		{
			bool isvalid = true;
			for(int j =1;j<k;j++) 
			{
				if(k-j == abs(i-Data[j]))  // (k,i) 与 (j,Data[j]) 
				{
					isvalid = false;
					break;
				} 
			}
			if(isvalid)
			{
				hashTable[i] = true;
				Data[k] = i;
				dfs(n,k+1);
				hashTable[i] = false;
			}
		}
	}
	
} 
int main()
{
	int n;
	cin >> n;
	c = 0;
	dfs(n,1);
	if(c==0) cout << "no solute!"<< endl;
	cout << "total:" << c << endl;
	return 0;
}

HDU2553 N皇后问题

HDU2553 N皇后问题
DFS+打表
打表很重要,不然很可能超时,来个TLE!

#include<iostream>
#include<string.h>
#include<math.h>
using namespace std;
int sum,n;
int x[15],y[15]={0};
int place(int k)
{
	int i;
	for(i=1;i<k;i++)
	{
		if(abs(k-i)==abs(x[k]-x[i])||x[k]==x[i])
		{
			return 0;
		}
	}
	return 1;
}
void dfs(int a)
{
	int i;
	if(a>n)
	{
		sum++;
		return ;
	}
	else
	for(i=1;i<=n;i++)
	{
		x[a] = i;
		if(place(a))
			dfs(a+1);
	}
}

int main()
{
	int i,j,n1;
	for(int i=1;i<=10;i++)
	{
		n = i;
		sum = 0;
		dfs(1);
		y[i] = sum;
	}
	while(cin >> n1 &&n1)
	{
		cout << y[n1] << endl;
	}
	return 0;
}

激光样式

这是一道2018蓝桥B组国赛题目

大概是就是有三十盏灯,排成一排,相邻两盏灯不能同时打开,问有多少种打开方式?当然全都不打开也算一种。
1.位运算 2.433s
偶然间看到一位大神的解法,觉得位运算是真的厉害,大概思想是用一个整型x来表示排列情况,将x左移一位,然后在于x本身相与,假如结果为0,就表明这是一种正确的排列方式,然后计数,代码真的是太简单了

#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
bool get(int x)
{
	if(x&(x<<1)) return false;
	else return true;
}
int main()
{
	int ans = 0;
	for(int i=0;i<1<<30;i++)
	{
		if(get(i)){
				ans++;
		}	
	}
	cout << ans << endl;
	return 0;
}

2.DFS
不过说起来还是深搜快,零点几秒,反正这是个填空题,能做出来就行呗。

#include<iostream>
#include<string.h>
using namespace std;
typedef long long ll;
ll ans;
int light[31];
void dfs(int x)
{
	if(x == 31)
	{
		ans++;
		return ;
	}
	if(light[x-1] == 0)
	{
		light[x] = 1;
		dfs(x+1);
		light[x] = 0;
	}
	dfs(x+1);
}
int main()
{
	dfs(1);
	cout << ans << endl;
	return 0;
}

【递归入门】走迷宫

Codeup5978【递归入门】走迷宫

#include<iostream>
using namespace std;
int a[20][20], endx, endy, m, n;
bool no = true;
int dx[4] = { 0,-1,0,1 }, dy[4] = { -1,0,1,0 };
 
struct Route {
	int x, y;
}route[5000];
 
 
void DFS(int x, int y, int num) 
{
	if (x == endx&&y == endy) 
	{
		for (int i = 0; i < num; i++) 
		{
			printf("(%d,%d)->",route[i].x,route[i].y);
		}
		printf("(%d,%d)\n",x,y);
		no = false;
		return;
	}
	route[num].x = x, route[num].y = y;
	for (int i = 0; i < 4; i++) 
	{
		if (a[x + dx[i]][y + dy[i]] == 1 && 1 <= x + dx[i] <= m && 1 <= y + dy[i] <= n) 
		{
			a[x][y] = 0;
			DFS(x + dx[i], y + dy[i], num + 1);
			a[x][y] = 1;
		}
	}
 
}
 
int main() {
	while (cin >> m >> n) 
	{
		for (int i = 1; i <= m; i++) 
		{
			for (int j = 1; j <= n; j++) 
			{
				cin >> a[i][j];
			}
		}
		int startx, starty;
		cin >> startx >> starty >> endx >> endy;
		DFS(startx, starty, 0);
		if (no) cout << -1 << endl;
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值