深度优先搜索
Posted Keep--Silent
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深度优先搜索相关的知识,希望对你有一定的参考价值。
深度优先搜索:Depth First Search
视频链接
本文讲解以DFS解决校选题
深度优先搜索常常复杂度较大,所以需要根据题目的题意进行适当剪枝。
目录
中档题-2 勋总的幂集 (15 分)
链接
dfs:15分
#include <bits/stdc++.h>
using namespace std;
set<vector<int>> ans;
int num[20];
void dfs(int pos, int n, vector<int> v)
//pos:第pos个数
//一共n个数,
//前面的集合是v
if (pos >= n)
ans.insert(v);
return;
dfs(pos + 1, n, v);
v.push_back(num[pos]);
dfs(pos + 1, n, v);
int main()
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> num[i];
vector<int> v;
dfs(0, n, v);
for (auto it : ans)
for (int i = 0; i < it.size(); i++)
printf("%d%s", it[i], i == it.size() - 1 ? "\\n" : " ");
return 0;
中档题-5 LIS (20 分)
链接
dfs:2分
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int A[4000 + 10], B[800000 + 10];
int ans;
map<int, int> pot;
int num[800000 + 10], sum[800000 + 10];
void dfs(int pos, int n, int pre, int cnt)
//pos:第pos个位置
//n:一共n个数
//pre:当前序列的最后一个数是pre
if (pos > n)
ans = max(cnt, ans);
return;
if (B[pos] == pre)
dfs(pos + 1, n, pre, cnt + 1);
else if (B[pos] < pre)
dfs(pos + 1, n, pre, cnt);
else
dfs(pos + 1, n, pre, cnt);
dfs(pos + 1, n, B[pos], cnt + 1);
int main(int argc, char *argv[])
int n, m, i, j;
cin >> n >> m;
for (j = 1; j <= n; j++)
scanf("%d", &A[j]);
pot[A[j]] = j;
for (i = 1; i <= m; i++)
scanf("%d", &B[i]);
B[i] = pot[B[i]];
dfs(1,m,0,0);
cout << ans << endl;
return 0;
dfs剪枝后:8分
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int A[4000 + 10], B[800000 + 10];
int ans;
map<int, int> pot;
int num[800000 + 10],sum[800000 + 10];
void dfs(int pos, int n, int pre, int cnt)
//pos:第pos个位置
//n:一共n个数
//pre:当前序列的最后一个数是pre
//cnt:当前序列的个数
//num[pos],sum[pos]:前面有sum[pos]个,最后一个数是num[pos]
if (pos > n)
ans = max(ans, cnt);
return;
if(num[pos]==0)
num[pos]=pre;
sum[pos]=cnt;
else if(cnt>sum[pos]&&pre<=num[pos])
sum[pos]=cnt;
num[pos]=pre;
else if(cnt<sum[pos]&&pre>=num[pos])
return ;
if (pre > B[pos])
dfs(pos + 1, n, pre, cnt);
else if (B[pos] == pre)
dfs(pos + 1, n, B[pos], cnt + 1);
else
dfs(pos + 1, n, pre, cnt);
dfs(pos + 1, n, B[pos], cnt + 1);
int main(int argc, char *argv[])
int n, m, i, j;
cin >> n >> m;
for (j = 1; j <= n; j++)
scanf("%d", &A[j]);
pot[A[j]] = j;
for (i = 1; i <= m; i++)
scanf("%d", &B[i]);
B[i] = pot[B[i]];
dfs(1, m, 0, 0);
cout << ans << endl;
return 0;
中档题-6 勋总的求偶日记 (25 分)
链接
dfs:10分
// O(n)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int num[100];
ll mod = 1e9 + 7;
ll dp[100][100];
ll dfs(int pos, int limit, ll cnt)
//pos:第pos位数
//limit :上界,1上界,0非上界
if (pos == -1)
return max(cnt, 1LL);
int n;
if (limit == 1)
n = num[pos];
else
n = 1;
ll ans = 1;
for (int i = 0; i <= n; i++)
if (i == 0)
ans *= dfs(pos - 1, limit && i == num[pos], cnt);
else
ans *= dfs(pos - 1, limit && i == num[pos], cnt + 1);
return ans % mod;
void solve(ll x)
int n = 0;
do
num[n++] = x % 2;
x /= 2;
while (x);
printf("%lld\\n", dfs(n - 1, 1, 0));
int main(int argc, char *argv[])
int T;
ll n;
cin >> T;
while (T--)
scanf("%lld", &n);
solve(n);
return 0;
dfs剪枝后(记忆化):25分
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int num[100];
ll mod = 1e9 + 7;
ll dp[100][100];
//数位dp
ll dfs(int pos, int limit, ll cnt)
//pos:第pos位数
//limit :上界,1上界,0非上界
if (pos == -1)
return max(cnt, 1LL);
int n;
if (limit == 1)
n = num[pos];
else
n = 1;
ll ans = 1;
if(limit==0)
if(dp[pos][cnt]!=-1)return dp[pos][cnt];
for (int i = 0; i <= n; i++)
if (i == 0)
ans *= dfs(pos - 1, limit && i == num[pos], cnt);
else
ans *= dfs(pos - 1, limit && i == num[pos], cnt + 1);
ans%=mod;
if(limit==0)
dp[pos][cnt]=ans;
return ans ;
void solve(ll x)
int n = 0;
do
num[n++] = x % 2;
x /= 2;
while (x);
printf("%lld\\n", dfs(n - 1, 1, 0));
int main(int argc, char *argv[])
int T;
ll n;
cin >> T;
memset(dp,-1,sizeof(dp));
while (T--)
scanf("%lld", &n);
solve(n);
return 0;
压轴题-1 贝贝的数组划分 (30 分)
链接
dfs:9分
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll num[20];
ll ans;
void dfs(int pos, int k, int n, ll t, ll sum)
//pos:第pos个数
//k:切k刀
//n:一共n个数
//t: 前面已切部分的按位与结果
//sum: 上一刀的数到当前位置的数的总和
if (pos >= n)
if (k == 0)
t &= sum;
ans = max(ans, t);
return;
dfs(pos + 1, k, n, t, sum + num[pos]);
dfs(pos + 1, k - 1, n, t & (sum + num[pos]), 0);
int main()
int n, k, T;
cin >> T;
while (T--)
cin >> n >> k;
for (int i = 0; i < n; i++)
cin >> num[i];
ans = 0;
dfs(0, k - 1, n, (1LL << 60) - 1, 0);
cout<<ans<<endl;
return 0;
dfs剪枝后:15分
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll num[20];
ll ans;
void dfs(int pos, int k, int n, ll t, ll sum)
//pos:第pos个数
//k:切k刀
//n:一共n个数
//t: 前面已切部分的按位与结果
//sum: 上一刀的数到当前位置的数的总和
if(t<=ans||k<0)return ;
if (pos >= n)
if (k == 0)
t &= sum;
ans = max(ans, t);
return;
dfs(pos + 1, k, n, t, sum + num[pos]);
dfs(pos + 1, k - 1, n, t & (sum + num[pos]), 0);
int main()
int n, k, T;
cin >> T;
while (T--)
cin >> n >> k;
for (int i = 0; i < n; i++)
cin >> num[i];
ans = 0;
dfs(0, k - 1, n, (1LL << 60) - 1, 0);
cout<<ans<<endl;
return 0;
压轴题-2 别装13 (30 分)
链接
dfs:10分
#include <bits/stdc++.h>
using namespace std;
const int SIZE = 100000 + 10;
vector<int> g[SIZE], path;
//path:路径
深度优先搜索(迷宫救人最短路径)
人工智障入门实战1使用深度优先搜索实现 Amazing-Brick 小游戏的自动控制