学习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)中素数的个数,该题可理解为在全排列的基础上进行了条件限制
- 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;
}
- 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: 【递归入门】组合+判断素数
#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皇后问题)
#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;
}
【递归入门】走迷宫
#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;
}