dfs算法训练

dfs算法训练

洛谷题单

https://www.luogu.com.cn/training/972732

开数组的范围

复制代码
1. int 全局二维
256MB = 256 × 1024 × 1024 = ≈ 6700 万 int
3000×3000 int:36MB ✅
4000×4000 int:64MB ✅
5000×5000 int:100MB ✅
8000×8000 int:256MB ❌ 刚好顶满
蓝桥全局 int 安全:≤ 5000×5000比赛里开到 3000×3000 完全稳

2. bool 全局二维
16000×16000 bool:256MB ❌ 顶满
10000×10000 bool:100MB ✅
5000×5000 bool:25MB ✅

全排列

输出 n 的全排列。

复制代码
样例输入:
	3
样例输出:
	1	2	3
    1	3	2
    2	1	3
    2	3	1
    3	1	2
    3	2	1

使用递归

c++ 复制代码
#include<bits/stdc++.h>
#define int long long
#define lll __uint128_t
#define PII pair<int ,int>
#define endl '\n'
using namespace std;

#define yn(ans) printf("%s\n", (ans)?"Yes":"No");
#define YN(ans) printf("%s\n", (ans)?"YES":"NO");
#define REP(i, e) for (int i = 0; i < (e); ++i)
#define REP1(i, s, e) for (int i = (s); i <=(e); ++i)
#define TESTS int t; cin >> t; while (t--)
#define TEST

const int N=2e5+10,M=1e3+10,mod=1e9+7;
int a[N],b[N],c[N],pre[N];
//全排列 
int n;
/**样例输入:
	3
样例输出:
	1	2	3
    1	3	2
    2	1	3
    2	3	1
    3	1	2
    3	2	1
**/
void dfs(int x){
	if(x==n+1){
		for(int i=1;i<=n;i++){
			cout<<a[i]<<" ";
		}
		cout<<endl;
		return;
	}
	for(int i=1;i<=n;i++){
		if(b[i]==0){
			b[i]=1;
			a[x]=i;
			dfs(x+1);
			a[x]=0;
			b[i]=0;
		} 
	}
}

signed main(){
	std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
	cin>>n;
	dfs(1); 
   	
	return 0;
}

使用next_permutation

方法一

主要还是去求这个,排列组合

c++ 复制代码
#include <bits/stdc++.h>
using namespace std;
int n,m;
int a[100];
int main()
{
    scanf("%d",&n);
    int tot=1;
    for(int i=1;i<=n;++i)
    {
        a[i]=i;
        tot*=i;
    }
    for(int i=1;i<=tot;++i)
    {
        for(int j=1;j<=n;++j) printf("    %d",a[j]);    //输出格式注意
        next_permutation(a+1,a+n+1);
        printf("\n");
    }
    return 0;
}

方法二

复制代码
#include<bits/stdc++.h>
#define int long long
#define lll __uint128_t
#define PII pair<int ,int>
#define endl '\n'
using namespace std;

#define yn(ans) printf("%s\n", (ans)?"Yes":"No");
#define YN(ans) printf("%s\n", (ans)?"YES":"NO");
#define REP(i, e) for (int i = 0; i < (e); ++i)
#define REP1(i, s, e) for (int i = (s); i <=(e); ++i)
#define TESTS int t; cin >> t; while (t--)
#define TEST

const int N=2e5+10,M=1e3+10,mod=1e9+7;
int a[N],b[N],c[N],pre[N];
//全排列 
int n;
/**样例输入:
	3
样例输出:
	1	2	3
    1	3	2
    2	1	3
    2	3	1
    3	1	2
    3	2	1
**/


signed main(){
	std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		a[i]=i;
	}
	do{
		for(int i=1;i<=n;i++){
			cout<<a[i]<<" ";
		}
		cout<<endl;
	}while(next_permutation(a+1,a+n+1));
   	
	return 0;
}

选或者不选

复制代码
#include<bits/stdc++.h>
using namespace std;

int n;                  // 物品个数
int a[25];              // 物品价值/重量等属性
bool vis[25];           // 标记选了哪些(可选)

// ========== 核心DFS模板 ==========
// k: 当前考虑第k个物品
// 其他参数:根据题目需要,如当前和、当前重量、当前价值等
void dfs(int k, int current_sum) {
    if(k > n) {         // 所有物品处理完毕
        // 在这里处理最终答案
        // 比如:更新最大/最小值,统计方案数,输出方案等
        ans = max(ans, current_sum);
        return;
    }
    
    // 选择1:不选第k个物品
    vis[k] = false;                     // 标记未选(可选)
    dfs(k + 1, current_sum);            // 状态不变,继续下一个
    
    // 选择2:选第k个物品
    vis[k] = true;                      // 标记已选(可选)
    dfs(k + 1, current_sum + a[k]);     // 状态更新,继续下一个
    // vis[k] = false;                  // 如果vis是全局数组,需要回溯
}

int main() {
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    
    dfs(1, 0);          // 从第1个开始,初始状态
    
    return 0;
}

常见变形

1. 求子集和等于target的方案数

复制代码
void dfs(int k, int sum) {
    if(k > n) {
        if(sum == target) ans++;
        return;
    }
    dfs(k + 1, sum);           // 不选
    dfs(k + 1, sum + a[k]);    // 选
}

2. 求选k个数的最大/最小和

cpp

复制

cpp 复制代码
void dfs(int pos, int cnt, int sum) {  // cnt: 已选个数
    if(cnt > k) return;        // 剪枝:选多了
    if(pos > n) {
        if(cnt == k) ans = max(ans, sum);
        return;
    }
    dfs(pos + 1, cnt + 1, sum + a[pos]);  // 选
    dfs(pos + 1, cnt, sum);               // 不选
}

3. 记录具体方案(回溯)

cpp

复制

cpp 复制代码
vector<int> path;

void dfs(int k, int sum) {
    if(k > n) {
        if(sum == target) {
            for(int x : path) cout << x << " ";
            cout << endl;
        }
        return;
    }
    // 不选
    dfs(k + 1, sum);
    // 选
    path.push_back(a[k]);
    dfs(k + 1, sum + a[k]);
    path.pop_back();           // 回溯
}

4. 有重量限制(背包类)

cpp

复制

cpp 复制代码
void dfs(int k, int weight, int value) {
    if(weight > W) return;     // 剪枝:超重
    if(k > n) {
        ans = max(ans, value);
        return;
    }
    dfs(k + 1, weight, value);                    // 不选
    dfs(k + 1, weight + w[k], value + v[k]);        // 选
}

BFS模板 --- 最短路径(迷宫问题)

c++ 复制代码
#include <bits/stdc++.h>
using namespace std;

const int N = 110;
int n, m;                    // 地图大小
char g[N][N];                // 地图:'.'表示空地,'#'表示障碍
int dist[N][N];              // 距离数组,-1表示未访问
int dx[4] = {-1, 0, 1, 0};   // 四个方向:上右下左
int dy[4] = {0, 1, 0, -1};

int bfs(int sx, int sy, int ex, int ey) {
    memset(dist, -1, sizeof dist);           // 初始化距离为-1(未访问)
    queue<pair<int, int>> q;
    
    dist[sx][sy] = 0;                        // 起点距离为0
    q.push({sx, sy});                        // 起点入队
    
    while (q.size()) {                       // 队列不为空
        auto t = q.front();                  // 取队首
        q.pop();
        
        int x = t.first, y = t.second;
        
        if (x == ex && y == ey)              // 到达终点
            return dist[x][y];
        
        for (int i = 0; i < 4; i++) {        // 遍历四个方向
            int a = x + dx[i], b = y + dy[i];
            
            // 边界检查 + 障碍检查 + 访问检查
            if (a < 0 || a >= n || b < 0 || b >= m) continue;
            if (g[a][b] == '#') continue;    // 障碍物
            if (dist[a][b] != -1) continue;  // 已访问过
            
            dist[a][b] = dist[x][y] + 1;     // 距离+1
            q.push({a, b});                    // 新点入队
        }
    }
    
    return -1;                               // 无法到达
}

int main() {
    cin >> n >> m;
    for (int i = 0; i < n; i++) cin >> g[i];
    
    int res = bfs(0, 0, n-1, m-1);           // 从左上到右下
    cout << res << endl;
    
    return 0;
}

DFS模板 --- 全排列/组合搜索

c++ 复制代码
#include <bits/stdc++.h>
using namespace std;

const int N = 10;
int n;
int path[N];                 // 当前路径/方案
bool used[N];                // 标记数字是否被使用

// 全排列:从n个数中选n个,有顺序
void dfs_permutation(int u) {    // u表示当前填到第几个位置
    if (u == n) {                // 填满了,输出方案
        for (int i = 0; i < n; i++) 
            cout << path[i] << ' ';
        cout << endl;
        return;
    }
    
    for (int i = 1; i <= n; i++) {   // 尝试每个数字
        if (!used[i]) {              // 如果i还没用过
            used[i] = true;          // 标记为使用
            path[u] = i;             // 填入当前位置
            
            dfs_permutation(u + 1);  // 递归填下一个位置
            
            used[i] = false;         // 回溯!恢复状态
        }
    }
}

// 组合:从n个数中选k个,无顺序(选法,不考虑排列)
void dfs_combination(int start, int k, int u) {
    // u:当前选了几个, start:从哪个数开始选(避免重复)
    if (u == k) {
        for (int i = 0; i < k; i++) 
            cout << path[i] << ' ';
        cout << endl;
        return;
    }
    
    for (int i = start; i <= n; i++) {   // 从start开始,避免选重复的
        path[u] = i;
        dfs_combination(i + 1, k, u + 1); // 下一个从i+1开始选
        // 这里不需要used数组,因为通过start控制不重复
    }
}

// DFS求连通块( Flood Fill )
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
char g[N][N];
bool vis[N][N];

void dfs_floodfill(int x, int y) {
    vis[x][y] = true;                    // 标记访问
    
    for (int i = 0; i < 4; i++) {
        int a = x + dx[i], b = y + dy[i];
        if (a < 0 || a >= n || b < 0 || b >= m) continue;
        if (g[a][b] == '#') continue;   // 不是目标区域
        if (vis[a][b]) continue;         // 访问过
        
        dfs_floodfill(a, b);             // 递归搜索连通块
    }
}

int main() {
    cout << "=== 全排列 ===" << endl;
    n = 3;
    dfs_permutation(0);
    
    cout << "\n=== 组合 C(4,2) ===" << endl;
    n = 4;
    dfs_combination(1, 2, 0);
    
    return 0;
}

记忆化搜索模板(DFS + DP)

c++ 复制代码
#include <bits/stdc++.h>
using namespace std;

const int N = 510;
int n, m;
int g[N][N], f[N][N];        // f[i][j] 表示从(i,j)出发的最大值

int dfs(int x, int y) {
    if (f[x][y] != -1) return f[x][y];   // 记忆化:算过直接返回
    
    f[x][y] = 1;                          // 至少包含自己
    
    // 四个方向搜索
    int dx[4] = {-1, 0, 1, 0};
    int dy[4] = {0, 1, 0, -1};
    
    for (int i = 0; i < 4; i++) {
        int a = x + dx[i], b = y + dy[i];
        if (a >= 0 && a < n && b >= 0 && b < m && g[a][b] < g[x][y]) {
            f[x][y] = max(f[x][y], dfs(a, b) + 1);  // 能滑下去就+1
        }
    }
    
    return f[x][y];
}

int main() {
    cin >> n >> m;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            cin >> g[i][j];
    
    memset(f, -1, sizeof f);   // 初始化为-1表示未计算
    
    int res = 0;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            res = max(res, dfs(i, j));
    
    cout << res << endl;
    return 0;
}

B3621 枚举元组

B3621 枚举元组 - 洛谷

思路

我们可以去使用dfs去枚举每一个位置,用a[pos]=i,去记录当前位的值

c++ 复制代码
void dfs(int pos){
	if(pos==n+1){
		for(int i=1;i<=n;i++){
			cout<<a[i]<<" ";
		}
		cout<<endl;
		return;
	}
	for(int i=1;i<=k;i++){
		a[pos]=i;
		dfs(pos+1);
	}
}

表示一个萝卜一个坑位的意思

a【pos】=i,表示地pos个位置是i

代码

c++ 复制代码
#include<bits/stdc++.h>
#define int long long
#define lll __uint128_t
#define PII pair<int ,int>
#define endl '\n'
using namespace std;
#define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印
#define YN(ans) printf("%s\n", (ans)?"YES":"NO");
#define REP(i, e) for (int i = 0; i < (e); ++i)
#define REP1(i, s, e) for (int i = (s); i <=(e); ++i)
#define TESTS int t; cin >> t; while (t--)
#define TEST
const int N=2e5+10,M=1e3+10,mod=1e9+7;
int a[N],b[N],c[N],pre[N];

int n;
int k;
void dfs(int pos){
	if(pos==n+1){
		for(int i=1;i<=n;i++){
			cout<<a[i]<<" ";
		}
		cout<<endl;
		return;
	}
	for(int i=1;i<=k;i++){
		a[pos]=i;
		dfs(pos+1);
	}
}

signed main(){

	std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>k;
    dfs(1);

	return 0;
}

B3622 枚举子集

B3622 枚举子集(递归实现指数型枚举) - 洛谷

思路

因为我们发现每个位置都有两种状态,我们就可以去定义两种状态的,一个0,一个1,每次都有两个可能

所以我们只需要定义两个位置的状态

c++ 复制代码
void dfs(int pos,int biao){
	if(biao==0){
		s+='N';
	}
	if(biao==1){
		s+='Y';
	}
	if(pos==n){
		cout<<s<<endl;
		s=s.substr(0,s.size()-1);//切除一下,相当于回塑 
		return; 
	}
	dfs(pos+1,0);
	dfs(pos+1,1);
	s=s.substr(0,s.size()-1);//回溯
}

代码

c++ 复制代码
#include<bits/stdc++.h>
#define int long long
#define lll __uint128_t
#define PII pair<int ,int>
#define endl '\n'
using namespace std;
#define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印
#define YN(ans) printf("%s\n", (ans)?"YES":"NO");
#define REP(i, e) for (int i = 0; i < (e); ++i)
#define REP1(i, s, e) for (int i = (s); i <=(e); ++i)
#define TESTS int t; cin >> t; while (t--)
#define TEST
const int N=2e5+10,M=1e3+10,mod=1e9+7;
int a[N],b[N],c[N],pre[N];

string s;
int n;
//用数字来表示状态 
void dfs(int pos,int biao){
	if(biao==0){
		s+='N';
	}
	if(biao==1){
		s+='Y';
	}
	if(pos==n){
		cout<<s<<endl;
		s=s.substr(0,s.size()-1);//切除一下,相当于回塑 
		return; 
	}
	dfs(pos+1,0);
	dfs(pos+1,1);
	s=s.substr(0,s.size()-1);
} 

signed main(){

	std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    cin>>n;
    dfs(1,0);
    dfs(1,1);

	return 0;
}

B3623 枚举排列

B3623 枚举排列(递归实现排列型枚举) - 洛谷

思路

选择两个数组一个数组记录第几个位置选的是什么,第二个就是有没有被选过,被选过的我们不要,没被选择的我们才要,记得回塑

c++ 复制代码
void dfs(int pos){
	if(pos==k+1){
		for(int i=1;i<=k;i++){
			cout<<a[i]<<" "; 
		}
		cout<<endl;
		return;
	}
	for(int i=1;i<=n;i++){
		if(b[i]==0){
			b[i]=1;	
		}else{
			continue;
		}
		a[pos]=i;
		dfs(pos+1);
		b[i]=0;
	}
	
}

代码

c++ 复制代码
#include<bits/stdc++.h>
#define int long long
#define lll __uint128_t
#define PII pair<int ,int>
#define endl '\n'
using namespace std;
#define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印
#define YN(ans) printf("%s\n", (ans)?"YES":"NO");
#define REP(i, e) for (int i = 0; i < (e); ++i)
#define REP1(i, s, e) for (int i = (s); i <=(e); ++i)
#define TESTS int t; cin >> t; while (t--)
#define TEST
const int N=2e5+10,M=1e3+10,mod=1e9+7;
int a[N],b[N],c[N],pre[N];

int n,k;
void dfs(int pos){
	if(pos==k+1){
		for(int i=1;i<=k;i++){
			cout<<a[i]<<" "; 
		}
		cout<<endl;
		return;
	}
	for(int i=1;i<=n;i++){
		if(b[i]==0){
			b[i]=1;	
		}else{
			continue;
		}
		a[pos]=i;
		dfs(pos+1);
		b[i]=0;
	}
	
}

signed main(){

	std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    cin>>n>>k;
    dfs(1);

	return 0;
}

P10448 组合型枚举

P10448 组合型枚举 - 洛谷

思路

我们可以去设置,两个数值记录,有没有选过和到底有没有用过,然后我们枚举只要从上一个数中枚举就行了

c++ 复制代码
for(int i=a[pos-1]+1;i<=n;i++){//关键代码
		if(b[i]==0){
			b[i]=1;
			
		}else{
			continue;
		}
		a[pos]=i;
		dfs(pos+1);
		b[i]=0;
	}

代码

c++ 复制代码
#include<bits/stdc++.h>
#define int long long
#define lll __uint128_t
#define PII pair<int ,int>
#define endl '\n'
using namespace std;
#define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印
#define YN(ans) printf("%s\n", (ans)?"YES":"NO");
#define REP(i, e) for (int i = 0; i < (e); ++i)
#define REP1(i, s, e) for (int i = (s); i <=(e); ++i)
#define TESTS int t; cin >> t; while (t--)
#define TEST
const int N=2e5+10,M=1e3+10,mod=1e9+7;
int a[N],b[N],c[N],pre[N];

int n,m;

void dfs(int pos){
	if(pos==m+1){
		for(int i=1;i<=m;i++){
			cout<<a[i]<<" ";
		}
		cout<<endl;
		return;
	}
	
	for(int i=a[pos-1]+1;i<=n;i++){
		if(b[i]==0){
			b[i]=1;
			
		}else{
			continue;
		}
		a[pos]=i;
		dfs(pos+1);
		b[i]=0;
	}
	
}

signed main(){

	std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    dfs(1);

	return 0;
}

P2089 烤鸡

P2089 烤鸡 - 洛谷

思路

c++ 复制代码
相当于每个位置只能放1,2,3,枚举的去,我们可以去计算当前的总数和,然后去枚举好就行了
但是会超时有的

void dfs(int pos,int sum1){
	if(sum1>n)return;
	if(pos==11&&sum1==n){
		string s;
		for(int i=1;i<=10;i++){
			s+=to_string(a[i])+" ";
		}
		ans.push_back(s);
		return;
	}
	for(int v=1;v<=3;v++){
		a[pos]=v;
		dfs(pos+1,sum1+v); 
	}
}

代码

c++ 复制代码
#include<bits/stdc++.h>
#define int long long
#define lll __uint128_t
#define PII pair<int ,int>
#define endl '\n'
using namespace std;
#define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印
#define YN(ans) printf("%s\n", (ans)?"YES":"NO");
#define REP(i, e) for (int i = 0; i < (e); ++i)
#define REP1(i, s, e) for (int i = (s); i <=(e); ++i)
#define TESTS int t; cin >> t; while (t--)
#define TEST
const int N=2e5+10,M=1e3+10,mod=1e9+7;
int a[N],b[N],c[N],pre[N];

int n;
vector<string>ans;

void dfs(int pos,int sum1){
	if(sum1>n)return;
	if(pos==11&&sum1==n){
		string s;
		for(int i=1;i<=10;i++){
			s+=to_string(a[i])+" ";
		}
		ans.push_back(s);
		return;
	}
	for(int v=1;v<=3;v++){
		a[pos]=v;
		dfs(pos+1,sum1+v); 
	}
}

signed main(){

	std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    dfs(1,0);
    if(ans.size()==0){
    	cout<<0<<endl;
	}else{
		cout<<ans.size()<<endl;
		for(auto&s : ans){
			cout<<s<<endl;
		}
	}
	return 0;
}

减枝

可以进行减枝

c++ 复制代码
if (n < 10 || n > 30) {
    cout << "0\n";
    return 0;
}

加一个这个代码

P15435[蓝桥杯 2025 国 Python B] 免费披萨

P15435 [蓝桥杯 2025 国 Python B\] 免费披萨 - 洛谷 (luogu.com.cn)](https://www.luogu.com.cn/problem/P15435) ![image-20260313212124002](https://img2024.cnblogs.com/blog/3621557/202604/3621557-20260409123819556-1828095243.png) ### 思路 我们可以去枚举每个位置的数值然后,去进行dfs,尝试枚举每个可能,然后填充后再进行判断计算出gcd的 ### 代码 ```c++ #include using namespace std; long long n,max_gcd=-1,minn=INT_MAX; int a[10],tot; void dfs(int pos) { if(pos==8) { string s=""; for(int i=1;i<=8;i++) s+=char(a[i]+'0'); for(int ins=0;ins<=8;ins++) for(int num=1;num<=8;num++) { string nine=s.substr(0,ins)+char(num+'0')+s.substr(ins); long long val=stoll(nine); long long now_gcd=__gcd(val,n); if(now_gcd>max_gcd) { max_gcd=now_gcd; minn=val; } else if(now_gcd==max_gcd) if(val>s; n=stoll(s); dfs(0);/ cout< #define int long long #define lll __uint128_t #define PII pair #define endl '\n' using namespace std; #define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印 #define YN(ans) printf("%s\n", (ans)?"YES":"NO"); #define REP(i, e) for (int i = 0; i < (e); ++i) #define REP1(i, s, e) for (int i = (s); i <=(e); ++i) #define TESTS int t; cin >> t; while (t--) #define TEST const int N=2e5+10,M=1e3+10,mod=1e9+7; int b[N],c[N],pre[N]; int a[20]; int n; int vis[1<<20];//记录有没有走过的 int ans[1<<20][20],tot=0; void output(){ for(int i=1;i<=1<>n; for(int i=1;i<=n;i++){ cout<<"O"; } cout< // 全局变量记录答案 long long ans = 0; // 参数说明: // idx: 当前处理第几个小朋友(0~6) // a: 已经分出去的第一种糖果数量 // b: 已经分出去的第二种糖果数量 void dfs(int index,int a,int b){ if(index==7){ if(a==9&&b==16){ ans++; } return; } for(int i=0;i<=9-a;i++){ for(int j=0;j<=16-b;j++){ int tatal=i+j; if(tatal>=2&&tatal<=5){ dfs(index+1,a+i,b+j); } } } } ``` ### 代码 ```c++ #include #define int long long #define lll __uint128_t #define PII pair #define endl '\n' using namespace std; #define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印 #define YN(ans) printf("%s\n", (ans)?"YES":"NO"); #define REP(i, e) for (int i = 0; i < (e); ++i) #define REP1(i, s, e) for (int i = (s); i <=(e); ++i) #define TESTS int t; cin >> t; while (t--) #define TEST const int N=2e5+10,M=1e3+10,mod=1e9+7; int ans=0; void dfs(int index,int a,int b){ if(index==7){ if(a==9&&b==16){ ans++; } return; } for(int i=0;i<=9-a;i++){ for(int j=0;j<=16-b;j++){ int tatal=i+j; if(tatal>=2&&tatal<=5){ dfs(index+1,a+i,b+j); } } } } signed main(){ std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); ans=0; dfs(0,0,0); cout< #define int long long #define lll __uint128_t #define PII pair #define endl '\n' using namespace std; #define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印 #define YN(ans) printf("%s\n", (ans)?"YES":"NO"); #define REP(i, e) for (int i = 0; i < (e); ++i) #define REP1(i, s, e) for (int i = (s); i <=(e); ++i) #define TESTS int t; cin >> t; while (t--) #define TEST const int N=2e5+10,M=1e3+10,mod=1e9+7; int a[N],b[N],c[N],pre[N]; int n; int len=0; //第一个表示下一个数的起始值,s表示 还剩下需要凑的数 void dfs(int stat,int s){ if(s==0){ if(len==1){ return; } for(int i=0;i0)cout<<"+"; cout<>n; dfs(1,n); return 0; } ``` ## P2386 放苹果 [P2386 放苹果 - 洛谷](https://www.luogu.com.cn/problem/P2386#submit) ![1775041874196](https://img2024.cnblogs.com/blog/3621557/202604/3621557-20260409123821198-103854466.png) ### 思路 这个题目主要还是不能选重复的然后就可以去想到记忆搜索法 - m == 0 或 n == 1:只有1种分法(全空/全放一个盘子) - m < 0 或 n == 0:0种分法(非法) 状态转移: - 情况1:至少有1个盘子空着 → 等价于 `dfs(m, n-1)`(少一个盘子,分法不变) - 情况2:所有盘子都有苹果 → 每个盘子先放1个,剩下 `m-n` 个苹果再分 → `dfs(m-n, n)` - 总方案数 = 情况1 + 情况2 公式:`dfs(m, n) = dfs(m, n-1) + dfs(m-n, n)` ### 代码 ```c++ #include #define int long long #define lll __uint128_t #define PII pair #define endl '\n' using namespace std; #define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印 #define YN(ans) printf("%s\n", (ans)?"YES":"NO"); #define REP(i, e) for (int i = 0; i < (e); ++i) #define REP1(i, s, e) for (int i = (s); i <=(e); ++i) #define TESTS int t; cin >> t; while (t--) #define TEST const int N=2e5+10,M=1e3+10,mod=1e9+7; int a[N],b[N],c[N],pre[N]; int me[205][205]; int n; int m,t; //m个苹果分给n个选手; int dfs(int m,int n){ if(m==0||n==1)return 1; if(m<0 ||n==0)return 0; if(me[m][n]!=-1) return me[m][n]; return me[m][n]=dfs(m,n-1)+dfs(m-n,n); } signed main(){ std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>t; for(int i=0;i>m>>n; cout< #define int long long #define lll __uint128_t #define PII pair #define endl '\n' using namespace std; #define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印 #define YN(ans) printf("%s\n", (ans)?"YES":"NO"); #define REP(i, e) for (int i = 0; i < (e); ++i) #define REP1(i, s, e) for (int i = (s); i <=(e); ++i) #define TESTS int t; cin >> t; while (t--) #define TEST const int N=2e5+10,M=1e3+10,mod=1e9+7; int a[N],b[N],c[N],pre[N]; int me[205][205]; int n; int m,t; signed main(){ std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int dp[205][205]; for(int i=0;i<=200;i++){ dp[i][1]=1;//i个苹果分给1个盘子 dp[0][i]=1;//0个苹果分给i个盘子 } for(int i=1;i<=200;i++){ for(int j=2;j<=200;j++){ if(i>=j){ dp[i][j]=dp[i][j-1]+dp[i-j][j]; }else{ dp[i][j]=dp[i][j-1]; } } } cin>>t; while(t--){ cin>>m>>n; cout< #define int long long #define lll __uint128_t #define PII pair #define endl '\n' using namespace std; #define yn(ans) printf("%s\n", (ans)?"Yes":"No"); #define YN(ans) printf("%s\n", (ans)?"YES":"NO"); #define REP(i, e) for (int i = 0; i < (e); ++i) #define REP1(i, s, e) for (int i = (s); i <=(e); ++i) #define TESTS int t; cin >> t; while (t--) #define TEST const int N=2e5+10,M=1e3+10,mod=1e9+7; int a[N],b[N],c[N],pre[N]; bool vis[200][200]; // 修复 1:改小! int m,n; vectors(n); int dx[8]={-1,-1,0,1,1,1,0,-1}; int dy[8]={0,1,1,1,0,-1,-1,-1}; int cnt=0; map galaxy; void dfs(int x,int y){ // 修复 2:|| 全部正确 if(x<0 || x>=n || y<0 || y>=m)return; if (s[x][y] == '.' || vis[x][y]) return; vis[x][y]=true; cnt++; for(int i=0;i<8;i++){ int nx=x+dx[i]; int ny=y+dy[i]; dfs(nx,ny); } } signed main(){ std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n>>m; //s.resize(n); for(int i=0;i>s[i]; } for(int i=0;i using namespace std; const int MAX = 1505; // 支持 1500x1500 int n, m; vector s; bool vis[MAX][MAX]; int dx[8] = {-1,-1,0,1,1,1,0,-1}; int dy[8] = {0,1,1,1,0,-1,-1,-1}; int bfs(int x, int y) { queue> q; q.push({x,y}); vis[x][y] = 1; int cnt = 1; while (!q.empty()) { auto [xx, yy] = q.front(); q.pop(); for (int i = 0; i < 8; i++) { int nx = xx + dx[i]; int ny = yy + dy[i]; if (nx >=0 && nx =0 && ny > n >> m; s.resize(n); for (int i = 0; i < n; i++) { cin >> s[i]; } map mp; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (s[i][j] == '*' && !vis[i][j]) { int sz = bfs(i, j); mp[sz]++; } } } int tot = mp.size(); long long max_gal = 0; for (auto &p : mp) { max_gal = max(max_gal, 1LL * p.first * p.second); } cout << tot << " " << max_gal << endl; return 0; } ## P1088 \[NOIP 2004 普及组\] 火星人 \[P1088 [NOIP 2004 普及组\] 火星人 - 洛谷](https://www.luogu.com.cn/problem/P1088) ![image-20260406162434889](https://img2024.cnblogs.com/blog/3621557/202604/3621557-20260409123822901-55773562.png) ![image-20260406162456903](https://img2024.cnblogs.com/blog/3621557/202604/3621557-20260409123823447-1026385521.png) ### 思路 就是去把所有的枚举一遍 用next_permutaiton跑枚举 ### 代码 ```c++ #include #define int long long #define lll __uint128_t #define PII pair #define endl '\n' using namespace std; #define yn(ans) printf("%s\n", (ans)?"Yes":"No"); #define YN(ans) printf("%s\n", (ans)?"YES":"NO"); #define REP(i, e) for (int i = 0; i < (e); ++i) #define REP1(i, s, e) for (int i = (s); i <=(e); ++i) #define TESTS int t; cin >> t; while (t--) #define TEST const int N=2e5+10,M=1e3+10,mod=1e9+7; int a[N],b[N],c[N],pre[N]; //全排列 int n; signed main(){ std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int m; cin>>n>>m; for(int i=1;i<=n;i++){ cin>>a[i]; } for(int i=1;i<=n;i++){ b[i]=i; } bool xx=false; int count=0; do{ if(xx==false){ for(int i=1;i<=n;i++){ if(a[i]!=b[i]){ break; } } xx=true; } count++; if(count==m+1){ for(int i=1;i<=n;i++){ cout< #define int long long #define lll __uint128_t #define PII pair #define endl '\n' using namespace std; #define yn(ans) printf("%s\n", (ans)?"Yes":"No"); #define YN(ans) printf("%s\n", (ans)?"YES":"NO"); #define REP(i, e) for (int i = 0; i < (e); ++i) #define REP1(i, s, e) for (int i = (s); i <=(e); ++i) #define TESTS int t; cin >> t; while (t--) #define TEST const int N=2e5+10,M=1e3+10,mod=1e9+7; int a[N],b[N],pre[N]; //全排列 int n; vector>g(4,vector(4,0)); bool check(int r, int c,int num){ for(int j=0;j<4;j++){//检查列 if(g[r][j]==num)return false; } for(int i=0;i<4;i++){ if(g[i][c]==num)return false; } int br=(r/2)*2; int bc=(c/2)*2; for(int i=br;i>g[i][j]; } } solve(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { cout << g[i][j] << (j < 3 ? ' ' : '\n'); } } return 0; } ``` ## B3862 图的遍历(简单版) [B3862 图的遍历(简单版) - 洛谷](https://www.luogu.com.cn/problem/B3862#submit) ![image-20260406174033497](https://img2024.cnblogs.com/blog/3621557/202604/3621557-20260409123824819-907608975.png) ### 思路 思路有两种,一种是从最大的开始找本身开始找哪些可以到达这个的最大值,叫 ### 反向图 ```c++ #include #define int long long #define lll __uint128_t #define PII pair #define endl '\n' using namespace std; #define yn(ans) printf("%s\n", (ans)?"Yes":"No"); #define YN(ans) printf("%s\n", (ans)?"YES":"NO"); #define REP(i, e) for (int i = 0; i < (e); ++i) #define REP1(i, s, e) for (int i = (s); i <=(e); ++i) #define TESTS int t; cin >> t; while (t--) #define TEST const int N=2e5+10,M=1e3+10,mod=1e9+7; int a[N],b[N],pre[N]; //全排列 int n,m; vectorg[N]; int ans[N]; bool vis[N]; void dfs(int u,int val){ vis[u]=true; ans[u]=val; for(int v:g[u]){ if(!vis[v]){ dfs(v,val); } } } signed main(){ std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n>>m; for(int i=0;i>u>>v; g[v].push_back(u); } for(int i=n;i>=1;i--){ if(!vis[i]){ dfs(i,i); } } for(int i=1;i<=n;i++){ cout< #define int long long #define lll __uint128_t #define PII pair #define endl '\n' using namespace std; #define yn(ans) printf("%s\n", (ans)?"Yes":"No"); #define YN(ans) printf("%s\n", (ans)?"YES":"NO"); #define REP(i, e) for (int i = 0; i < (e); ++i) #define REP1(i, s, e) for (int i = (s); i <=(e); ++i) #define TESTS int t; cin >> t; while (t--) #define TEST const int N=2e5+10,M=1e3+10,mod=1e9+7; int a[N],b[N],pre[N]; //全排列 int n,m; vectorg[N]; int ans[N]; bool vis[N]; int max1; void dfs(int u){ vis[u]=true; max1=max(max1,u); for(int v:g[u]){ if(!vis[v]){ dfs(v); } } } signed main(){ std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n>>m; for(int i=0;i>u>>v; g[u].push_back(v); } for(int i=1;i<=n;i++){ memset(vis,0,sizeof(vis)); max1=i; dfs(i); cout< #define int long long #define lll __uint128_t #define PII pair #define endl '\n' using namespace std; #define yn(ans) printf("%s\n", (ans)?"Yes":"No"); #define YN(ans) printf("%s\n", (ans)?"YES":"NO"); #define REP(i, e) for (int i = 0; i < (e); ++i) #define REP1(i, s, e) for (int i = (s); i <=(e); ++i) #define TESTS int t; cin >> t; while (t--) #define TEST const int N=2e5+10,M=1e3+10,mod=1e9+7; int a[N],b[N],pre[N]; //全排列 int n,m; vectorg[N]; int ans=0; const int num[] = {6,2,5,5,4,5,6,3,7,6}; signed main(){ std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n; a[0] = 6; //数字 0 有 6 个火柴 for (int i = 1;i <= 2000;i++){ for (int j = i;j;j /= 10){ //从最高位开始,一个数位一个数位地加上火柴数 a[i] += num[j % 10]; } } for (int i = 0;i <= 1000;i++){ for (int j = 0;j <= 1000;j++){ if (a[i] + a[j] + a[i + j] + 4 == n){ //a[i] 就是第一个数,a[j] 就是第二个数。 ans++; //a[i + j]就是第三个数。加上的 4 就是 + 和 =。 } } } cout << ans << endl; return 0; } ``` ## P8801 \[蓝桥杯 2022 国 B\] 最大数字 题解 \[P8801 [蓝桥杯 2022 国 B\] 最大数字 - 洛谷](https://www.luogu.com.cn/problem/P8801) ![1775476918706](https://img2024.cnblogs.com/blog/3621557/202604/3621557-20260409123826205-1785030752.png) ### 思路 分情况去讨论,可以分两种都可以让数字变成9,分一种,分第二种,最后如果都不能那就优先把加的全部用上。 如果要用非常暴力的方法去解决的话也是可以的 ```c++ #include #define int long long #define lll __uint128_t #define PII pair #define endl '\n' using namespace std; #define yn(ans) printf("%s\n", (ans)?"Yes":"No"); #define YN(ans) printf("%s\n", (ans)?"YES":"NO"); #define REP(i, e) for (int i = 0; i < (e); ++i) #define REP1(i, s, e) for (int i = (s); i <=(e); ++i) #define TESTS int t; cin >> t; while (t--) #define TEST const int N=2e5+10,M=1e3+10,mod=1e9+7; //int a[N],b[N],pre[N]; int n,a,b; string s,ans; void dfs(int k,int c,int d,string str){ if(k==n){ if(str>ans){ ans=str; } return; } for(int i=c;i<=a;i++){ for(int j=d;j<=b;j++){ int num = str[k] - '0'; num = (num + i) % 10; // 先加i次 num = (num - j + 10) % 10; // 再减j次 str[k]=num+'0'; dfs(k+1,i,j,str); } } } signed main(){ std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>s; cin>>a>>b; n=s.size(); dfs(0,0,0,s); cout< #define int long long #define lll __uint128_t #define PII pair #define endl '\n' using namespace std; #define yn(ans) printf("%s\n", (ans)?"Yes":"No"); #define YN(ans) printf("%s\n", (ans)?"YES":"NO"); #define REP(i, e) for (int i = 0; i < (e); ++i) #define REP1(i, s, e) for (int i = (s); i <=(e); ++i) #define TESTS int t; cin >> t; while (t--) #define TEST const int N=2e5+10,M=1e3+10,mod=1e9+7; //int a[N],b[N],pre[N]; int n,a,b; string s,ans; void dfs(int k,int c,int d,string str){ if(k==n){ if(str>ans){ ans=str; } return; } int x=9-str[k]+'0'; int y=str[k]-'0'+1; int old=str[k]; if(c+x<=a&&d+y<=b){//如果两种都能变九,都尝试一下 str[k]='9'; dfs(k+1,c+x,d,str); dfs(k+1,c,d+y,str); }else if(c+x<=a){//只有一可以 str[k]='9'; dfs(k+1,c+x,d,str); }else if(d+y<=b){//只有二可以 str[k]='9'; dfs(k+1,c,d+y,str); }else{ str[k]+=a-c; dfs(k+1,a,d,str); } } signed main(){ std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>s; cin>>a>>b; n=s.size(); dfs(0,0,0,s); cout< #define int long long #define lll __uint128_t #define PII pair #define endl '\n' using namespace std; #define yn(ans) printf("%s\n", (ans)?"Yes":"No"); #define YN(ans) printf("%s\n", (ans)?"YES":"NO"); #define REP(i, e) for (int i = 0; i < (e); ++i) #define REP1(i, s, e) for (int i = (s); i <=(e); ++i) #define TESTS int t; cin >> t; while (t--) #define TEST const int N=2e5+10,M=1e3+10,mod=1e9+7; //int a[N],b[N],pre[N]; int n; int num[20]={0,5,5,10,10,15,15,20,20,25,25}; bool b[210]; int ans=0; void dfs(int k,int s){ if(k>10){ b[s]=1; for(int i=1;i<=10;i++){ cout< #define int long long #define lll __uint128_t #define PII pair #define endl '\n' using namespace std; #define yn(ans) printf("%s\n", (ans)?"Yes":"No"); #define YN(ans) printf("%s\n", (ans)?"YES":"NO"); #define REP(i, e) for (int i = 0; i < (e); ++i) #define REP1(i, s, e) for (int i = (s); i <=(e); ++i) #define TESTS int t; cin >> t; while (t--) #define TEST const int N=2e5+10,M=1e3+10,mod=1e9+7; int a[N],b[N],pre[N]; int t; string str="123456789"; maph; queueq; void bfs(){ q.push(str); h[str]=1; while(q.size()){ string s=q.front(); q.pop(); string v[4]={s,s,s,s};//这里的 s 代表的不是字符 s,而是 s 字符串。 //左上角区域逆时针旋转 v[0][0]=s[1],v[0][4]=s[3]; v[0][1]=s[4],v[0][3]=s[0]; //右上角区域逆时针旋转 v[1][1]=s[2],v[1][5]=s[4]; v[1][2]=s[5],v[1][4]=s[1]; v[2][3]=s[4];v[2][6]=s[3];//左下角区域逆时针旋转 v[2][4]=s[7];v[2][7]=s[6]; v[3][4]=s[5];v[3][7]=s[4];//右下角区域逆时针旋转 v[3][5]=s[8];v[3][8]=s[7]; //主要因为这里是逆向的,所以就是这样子要寻找逆向的旋转 for(int i=0;i<4;i++){ if(!h[v[i]]){ h[v[i]]=h[s]+1; if (v[i]==str) break; q.push(v[i]); } } } } signed main(){ std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>t; bfs(); while(t--){ string s; for(int i=0;i<9;i++){ char c; cin>>c; s+=c; } cout< #define int long long #define lll __uint128_t #define PII pair #define endl '\n' using namespace std; #define yn(ans) printf("%s\n", (ans)?"Yes":"No"); #define YN(ans) printf("%s\n", (ans)?"YES":"NO"); #define REP(i, e) for (int i = 0; i < (e); ++i) #define REP1(i, s, e) for (int i = (s); i <=(e); ++i) #define TESTS int t; cin >> t; while (t--) #define TEST const int N=2e5+10,M=1e3+10,mod=1e9+7; int a[N],b[N],pre[N]; int ans=0; int r=0,t=0; void pd(){ if(!((a[1]+a[2]+a[3]+a[4]+a[5])%5))return; if(!((a[6]+a[7]+a[8]+a[9]+a[10])%5))return; if(!((a[11]+a[12]+a[13]+a[14]+a[15])%5))return; if(!((a[16]+a[17]+a[18]+a[19]+a[20])%5))return; if(!((a[21]+a[22]+a[23]+a[24]+a[25])%5))return; if(!((a[1]+a[6]+a[11]+a[16]+a[21])%5))return; if(!((a[2]+a[7]+a[12]+a[17]+a[22])%5))return; if(!((a[3]+a[8]+a[13]+a[18]+a[23])%5))return; if(!((a[4]+a[9]+a[14]+a[19]+a[24])%5))return; if(!((a[5]+a[10]+a[15]+a[20]+a[25])%5))return; if(!((a[1]+a[7]+a[13]+a[19]+a[25])%5))return; if(!((a[5]+a[9]+a[13]+a[17]+a[21])%5))return; ans++; } void dfs(int k){ if(k==26){ pd(); } if(r<=12){ a[k]=1; r++; dfs(k+1); r--; } if(t<=11){ a[k]=0; t++; dfs(k+1); t--; } } signed main(){ std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); dfs(1); cout< using namespace std; int dd[] = {1, 2, 3}; int calc(int a, int b, int op){ if (op == 1) return a & b; if (op == 2) return a | b; if (op == 3) return a ^ b; } int main() { int ans = 0; for (int a : dd) for (int b : dd) for (int c : dd) for (int d : dd) for (int e : dd) for (int f : dd) for (int g : dd) for (int h : dd) for (int i : dd) for (int j : dd) { int k = calc(1, 0, a), l = calc(0, 1, b), m = calc(1, 0, c), n = calc(0, 1,d); int o = calc(k, l, e), p = calc(l, m, f), q = calc(m, n, g); int r = calc(o, p, h), s = calc(p, q, i); int t = calc(r, s, j); if (t == 1) ans++; } cout << ans << endl; return 0; } ``` ### dfs ```c++ #include using namespace std; int ans; // 记录满足条件的方案数 int arr[5][5]; // arr[i][j] 表示第i行第j列的值(0≤i≤4, 0≤j≤4-i) // DFS遍历每个门电路位置,尝试三种操作 void dfs(int i, int j) { // 终止条件:已经处理完所有10个门电路(i从1到4,共4+3+2+1=10个) if (i == 5) { if (arr[4][0] == 1) ans++; // 检查最终输出是否为1 return; } // 计算下一个要处理的位置 int x = i, y = j + 1; if (y > 4 - x) { // 如果j超出当前行的范围(第i行有5-i个元素) x++; // 转到下一行 y = 0; // 从下一行的第0列开始 } // 当前门电路的两个输入 int u = arr[i-1][j]; // 左上方的值 int v = arr[i-1][j+1]; // 右上方的值 // 尝试三种门电路,分别递归 arr[i][j] = u & v; dfs(x, y); // 与门 arr[i][j] = u | v; dfs(x, y); // 或门 arr[i][j] = u ^ v; dfs(x, y); // 异或门 } int main() { // 初始化第0层(输入层) arr[0][0] = arr[0][2] = arr[0][4] = 1; // In[0]=1, In[2]=1, In[4]=1 // arr[0][1] 和 arr[0][3] 默认为0(全局变量初始化为0) dfs(1, 0); // 从第1行第0列开始填门电路 cout << ans << endl; return 0; } ```

相关推荐
Godjian2 个月前
C++小白训练第十三天
算法学习
程序猿看视界1 年前
「读书计划」《啊哈!算法》7日结构化学习规划
数据结构·编程·算法竞赛·学习计划·算法学习
AI研习星球1 年前
数据分析-50-客户价值分析-用Python实现RFM模型
python·机器学习·自然语言处理·数据挖掘·数据分析·算法学习·论文辅导
liangbm32 年前
数学建模笔记—— 非线性规划
笔记·python·数学建模·matlab·算法学习·非线性规划·优化问题
小兔子编程2 年前
算法学习012-不同路径 c++动态规划算法实现 中小学算法思维学习 信奥算法解析
算法·动态规划·算法学习·c++算法思维·中小学c++·c++不同路径·c++动态规划
小兔子编程2 年前
算法学习007-进制转换 c++递归算法实现 中小学算法思维学习 信奥算法解析
算法·c++递归算法·c++进制转换·算法学习·c++算法思维·中小学c++·c++算法案例