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去枚举每一个位置,用apos=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)

思路

我们可以去枚举每个位置的数值然后,去进行dfs,尝试枚举每个可能,然后填充后再进行判断计算出gcd的

代码

c++ 复制代码
#include<bits/stdc++.h>
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<minn) 
						minn=val;
			}
		return;
	}
	for(int i=1;i<=8;i++)
	{
		bool flag=0;
		for(int j=1;j<=pos;j++)
			if(a[j]==i)
			{
				flag=1;
				break;
			}
		if(!flag)
		{
			a[pos+1]=i;
			dfs(pos+1);
		}
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	string s;
	cin>>s;
	n=stoll(s);
	dfs(0);/
	cout<<minn;
	return 0;
}

P6183 USACO10MAR The Rock Game S

P6183 [USACO10MAR The Rock Game S - 洛谷 (luogu.com.cn)](https://www.luogu.com.cn/problem/P6183)

思路:找到与当前只差一个的方案,判断是否走过,记录并输出。

Q:如何判断是否走过呢。

A:考虑转化,加入将O记为0,X记为1,这样每个状态都可以转化为一个二进制数,将他转换为十进制存储,判断也按十进制判断即可。

我们通过判断

考虑转化,加入将O记为0,X记为1,这样每个状态都可以转化为一个二进制数,将他转换为十进制存储,判断也按十进制判断即可。

c++ 复制代码
void output(){//输出
	for(int i=1;i<=1<<n;i++){
		for(int j=1;j<=n;j++){
			cout<<(ans[i][j]?'X':'O');
		}
		cout<<endl;
	}
}
c++ 复制代码
int cacl(){//转换二进制
	int ans=0;
	for(int i=1;i<=n;i++){
		ans=ans*2+a[i];
	}
	return ans;
}

然后dfs去扫描

到底有没有

c++ 复制代码
void dfs(int pos){
	if(pos==(1<<n)){
		output();//找到一组 
		exit(0);
	}
	for(int i=1;i<=n;i++){
		a[i]=!a[i];
		if(vis[cacl()]){
			a[i]=!a[i];
			continue;
		}
		vis[cacl()]=true;
		for(int j=1;j<=n;j++){
			ans[pos][j]=a[j];//存储答案 
		}
		dfs(pos+1);//继续搜索下一个 
		vis[cacl()]=false;//回溯 
		a[i]=!a[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 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;i++){
		for(int j=1;j<=n;j++){
			cout<<(ans[i][j]?'X':'O');
		}
		cout<<endl;
	}
}
int cacl(){
	int ans=0;
	for(int i=1;i<=n;i++){
		ans=ans*2+a[i];
	}
	return ans;
}
void dfs(int pos){
	if(pos==(1<<n)){
		output();//找到一组 
		exit(0);
	}
	for(int i=1;i<=n;i++){
		a[i]=!a[i];
		if(vis[cacl()]){
			a[i]=!a[i];
			continue;
		}
		vis[cacl()]=true;
		for(int j=1;j<=n;j++){
			ans[pos][j]=a[j];//存储答案 
		}
		dfs(pos+1);//继续搜索下一个 
		vis[cacl()]=false;//回溯 
		a[i]=!a[i];//注意:不能颠倒,被坑了一次 
	} 
} 
signed main(){

	std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++){
    	cout<<"O";
	}
	cout<<endl;
	vis[0]=true;//0直接是用过的 
    dfs(1);//从1开始搜索
	 
	return 0;
}

P13886 蓝桥杯 2023 省 Python A 分糖果

P13886 [蓝桥杯 2023 省 Python A 分糖果 - 洛谷 (luogu.com.cn)](https://www.luogu.com.cn/problem/P13886)

思路

我们可以这样想,每个位置可以分糖果的种类可以有两种,要么第一种要么第二种

,我们就判断当前位置可以分的第一个的数量和第二个数量进行枚举。

c++ 复制代码
枚举位置的情况,然后
#include <stdio.h>

// 全局变量记录答案
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<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 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<<ans<<endl;
	return 0;
}

P2404 自然数的拆分问题

P2404 自然数的拆分问题 - 洛谷 (luogu.com.cn)

思路

复制代码
题目说是数字要从大到小,我们就就可以去枚举单前的数的范围
stat-s
直接拿这两个数去做参数,第一个表示下一个数的起始值,s表示 还剩下需要凑的数

代码

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 len=0;
//第一个表示下一个数的起始值,s表示 还剩下需要凑的数
void dfs(int stat,int s){
    if(s==0){
        if(len==1){
            return;
        }
       for(int i=0;i<len;i++){
           if(i>0)cout<<"+";
           cout<<a[i];
       }
       cout<<endl;
       return;
    }
    for(int i=stat;i<=s;i++){
        a[len++]=i;
        dfs(i,s-i);//回塑
        len--;
    }
}
signed main(){

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

	return 0;
}

P2386 放苹果

P2386 放苹果 - 洛谷

思路

这个题目主要还是不能选重复的然后就可以去想到记忆搜索法

复制代码
- 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<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 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<t;i++){
   		memset(me,-1,sizeof(me));
   		cin>>m>>n;
   		cout<<dfs(m,n)<<endl;
	   }
	return 0;
}

dp代码

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 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<<dp[m][n]<<endl;
	}

	return 0;
}

P6566 NOI Online #3 入门组 观星

P6566 [NOI Online #3 入门组 观星 - 洛谷](https://www.luogu.com.cn/problem/P6566#submit)

复制代码
5 7
*......
..**..*
.*...*.
...*...
....*..

3 4

思路

就是dfs和bfs

代码

dfs

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];

bool vis[200][200];  // 修复 1:改小!
int m,n;
vector<string>s(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<int, int> 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<n;i++){
    	cin>>s[i]; 
	}
	
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			if(s[i][j]=='*'&&!vis[i][j]){
				cnt=0;
				dfs(i,j);
				galaxy[cnt]++;
			}
		}
	}
	
	int galaxy_cnt=galaxy.size();
	int max_size=0;
	for(auto &p:galaxy){
		max_size=max(max_size,p.first * p.second);
	}
	cout<<galaxy_cnt<<" "<<max_size<<endl; 

	return 0;
}

bfs

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

const int MAX = 1505; // 支持 1500x1500

int n, m;
vector<string> 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<pair<int,int>> 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 <n && ny >=0 && ny <m && !vis[nx][ny] && s[nx][ny] == '*') {
                vis[nx][ny] = 1;
                cnt++;
                q.push({nx, ny});
            }
        }
    }
    return cnt;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n >> m;
    s.resize(n);
    for (int i = 0; i < n; i++) {
        cin >> s[i];
    }

    map<int, int> 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)

思路

就是去把所有的枚举一遍

用next_permutaiton跑枚举

代码

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;



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<<a[i]<<" ";
		}
		break;
	}
		
	}while(next_permutation(a+1,a+n+1));
   	
	return 0;
}

B4482 语言月赛 202601 数字游戏 II

搜索加判断

B4482 [语言月赛 202601 数字游戏 II - 洛谷](https://www.luogu.com.cn/problem/B4482)

思路

就是搜索加回塑

我们先找到要填的来,然后去依次填写这个数,找到合适的,并且如果不行就要回到上一个去再找。

主要判断行和列和2x2怎么去判断一下。

代码

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],pre[N];
//全排列 
int n;


vector<vector<int>>g(4,vector<int>(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<br+2;i++){
		for(int j=bc;j<bc+2;j++){
			if(g[i][j]==num)return false;
		}
	} 
	return true;
} 
bool nextfind(int &r,int &c){
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			if(g[i][j]==0){
				r=i,c=j;
				return true;
			}
		}
	}
	return false;
} 

bool solve(){
	int r,c;
	//如果没有空位置,代表解完了。 
	if(!nextfind(r,c))return true;
	//尝试1-4; 
	for(int num=1;num<=4;num++){
		if(check(r,c,num)){
			g[r][c]=num;
			if (solve()) return true;//递归求解 
			g[r][c]=0;//回塑 
		}
	}
	return false;//无解 
}
signed main(){
	std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
	
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			cin>>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 图的遍历(简单版) - 洛谷

思路

思路有两种,一种是从最大的开始找本身开始找哪些可以到达这个的最大值,叫

反向图

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],pre[N];
//全排列 
int n,m;
vector<int>g[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<m;i++){
    	int u,v;
    	cin>>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<<ans[i]<<" ";
	}
   	
	return 0;
}

最基础的暴力去搜索那个是最大的

搜索图

复制代码
void dfs(int u){
	vis[u]=true;
	max1=max(max1,u);
	for(int v:g[u]){
		if(!vis[v]){
			dfs(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],pre[N];
//全排列 
int n,m;
vector<int>g[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<m;i++){
    	int u,v;
    	cin>>u>>v;
    	g[u].push_back(v);
	}
	for(int i=1;i<=n;i++){
		memset(vis,0,sizeof(vis));
		max1=i;
		dfs(i);
		cout<<max1<<(i<n?' ':'\n');
	}
   	
	return 0;
}

P1149 NOIP 2008 提高组 火柴棒等式

思路

暴力

把1-2000的数的都存在数组中

代码

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],pre[N];
//全排列 
int n,m;
vector<int>g[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)

思路

分情况去讨论,可以分两种都可以让数字变成9,分一种,分第二种,最后如果都不能那就优先把加的全部用上。

如果要用非常暴力的方法去解决的话也是可以的

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],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<<ans<<endl;
	return 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],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<<ans<<endl;
	return 0;
}

P12266 蓝桥杯 2024 国 Python B 不同的总分值

思路

是选这个和不选这个可以达到的和

代码

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],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<<b[i]<<" ";
		}
		memset(b,0,sizeof(b));
		cout<<endl;
		return;
	}
	dfs(k+1,s),dfs(k+1,s+num[k]);
}

signed main(){
	std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    dfs(1,0);
//    for(int i=0;i<=150;i++){
//    	ans+=b[i];
//	}
	cout<<ans<<endl;
	return 0;
}

P10578 蓝桥杯 2024 国 A 旋转九宫格

P10578 [蓝桥杯 2024 国 A 旋转九宫格 - 洛谷](https://www.luogu.com.cn/problem/P10578)

思路

这个我们可以逆着推,为什么是bfs呢,就是我们根据当前的状态去向外扩展,所有的状态,这个时候我们就可以去把这个数的状态去全部得到

直接看代码

代码

bfs

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],pre[N];
int t;
string str="123456789";
map<string,int>h;

queue<string>q;

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<<h[s]-1<<endl; 
	} 
   	
	return 0;
}

P10386 蓝桥杯 2024 省 A 五子棋对弈

P10386 [蓝桥杯 2024 省 A 五子棋对弈 - 洛谷](https://www.luogu.com.cn/problem/P10386)

思路

博弈我们可以将他看出一维的数组,然后因为棋盘都是5x5要赢的话只有12种情况,我们可以把这些全部的排列全部写出来,然后去判断到底那些是要的

代码

bfs

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],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<<ans<<endl;
	return 0;
}

P13877 蓝桥杯 2023 省 Java A 与或异或

P13877 [蓝桥杯 2023 省 Java A 与或异或 - 洛谷](https://www.luogu.com.cn/problem/P13877)

暴力枚举

主要这个门一共有10个选择我们可以直接去枚举这个10种状态。

代码

c++ 复制代码
#include <iostream>

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 <iostream>
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;
}
相关推荐
yashuk2 个月前
C语言实现PAT习题题解及算法学习笔记,附SQLite介绍
c语言·sqlite·开源项目·算法学习·pat习题
yashuk2 个月前
C语言实现PAT练习及算法学习笔记,还有SQLite介绍
c语言·sqlite·开源项目·算法学习·pat练习
Godjian4 个月前
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++算法案例