如何用DFS算法训练识别模型?
摘要:dfs算法训练 洛谷题单 https:www.luogu.com.cntraining972732 开数组的范围 1. int 全局二维 256MB = 256 × 1024 ×
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
使用递归
#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
方法一
主要还是去求这个,排列组合
#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
复制
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
复制
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
复制
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模板 — 最短路径(迷宫问题)
#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模板 — 全排列/组合搜索
#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)
#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,去记录当前位的值
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
代码
#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,每次都有两个可能
所以我们只需要定义两个位置的状态
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);//回溯
}
代码
#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 枚举排列(递归实现排列型枚举) - 洛谷
思路
选择两个数组一个数组记录第几个位置选的是什么,第二个就是有没有被选过,被选过的我们不要,没被选择的我们才要,记得回塑
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;
}
}
代码
#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 组合型枚举 - 洛谷
思路
我们可以去设置,两个数值记录,有没有选过和到底有没有用过,然后我们枚举只要从上一个数中枚举就行了
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;
}
代码
#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 烤鸡 - 洛谷
思路
相当于每个位置只能放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);
}
}
代码
#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;
}
减枝
可以进行减枝
if (n < 10 || n > 30) {
cout << "0\n";
return 0;
}
加一个这个代码
P15435[蓝桥杯 2025 国 Python B] 免费披萨
[P15435 蓝桥杯 2025 国 Python B] 免费披萨 - 洛谷 (luogu.com.cn)
思路
我们可以去枚举每个位置的数值然后,去进行dfs,尝试枚举每个可能,然后填充后再进行判断计算出gcd的
代码
#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)
思路:找到与当前只差一个的方案,判断是否走过,记录并输出。
Q:如何判断是否走过呢。
A:考虑转化,加入将O记为0,X记为1,这样每个状态都可以转化为一个二进制数,将他转换为十进制存储,判断也按十进制判断即可。
我们通过判断
考虑转化,加入将O记为0,X记为1,这样每个状态都可以转化为一个二进制数,将他转换为十进制存储,判断也按十进制判断即可。
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;
}
然后dfs去扫描
到底有没有
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];//注意:不能颠倒,被坑了一次
}
}
代码
#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)
思路
我们可以这样想,每个位置可以分糖果的种类可以有两种,要么第一种要么第二种
,我们就判断当前位置可以分的第一个的数量和第二个数量进行枚举。
枚举位置的情况,然后
#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);
}
}
}
}
代码
#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表示 还剩下需要凑的数
代码
#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)
代码
#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代码
#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 入门组] 观星 - 洛谷
5 7
*......
..**..*
.*...*.
...*...
....*..
3 4
思路
就是dfs和bfs
代码
dfs
#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 普及组] 火星人 - 洛谷
思路
就是去把所有的枚举一遍
用next_permutaiton跑枚举
代码
#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 - 洛谷
思路
就是搜索加回塑
我们先找到要填的来,然后去依次填写这个数,找到合适的,并且如果不行就要回到上一个去再找。
主要判断行和列和2x2怎么去判断一下。
代码
#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 图的遍历(简单版) - 洛谷
思路
思路有两种,一种是从最大的开始找本身开始找哪些可以到达这个的最大值,叫
反向图
#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);
}
}
}
#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的数的都存在数组中
代码
#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] 最大数字 - 洛谷
思路
分情况去讨论,可以分两种都可以让数字变成9,分一种,分第二种,最后如果都不能那就优先把加的全部用上。
如果要用非常暴力的方法去解决的话也是可以的
#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;
}
代码
#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] 不同的总分值
思路
是选这个和不选这个可以达到的和
代码
#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] 旋转九宫格 - 洛谷
思路
这个我们可以逆着推,为什么是bfs呢,就是我们根据当前的状态去向外扩展,所有的状态,这个时候我们就可以去把这个数的状态去全部得到
直接看代码
代码
bfs
#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] 五子棋对弈 - 洛谷
思路
博弈我们可以将他看出一维的数组,然后因为棋盘都是5x5要赢的话只有12种情况,我们可以把这些全部的排列全部写出来,然后去判断到底那些是要的
代码
bfs
#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] 与或异或 - 洛谷
暴力枚举
主要这个门一共有10个选择我们可以直接去枚举这个10种状态。
代码
#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
#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;
}
