1、实现可行性剪枝
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
int n, k, sum, ans;
int a[40];
void dfs(int i, int cnt, int s)
{
//剪枝
if (cnt > k)
{
return;
}
if (s > sum)
{
return;
}
if (i == n)
{
if (cnt == k && s == sum)
{
ans++;
}
return;
}
dfs(i + 1, cnt, s);
dfs(i + 1, cnt + 1, s + a[i]);
}
int main()
{
n = 30;
k = 8;
sum = 200;
for (int i = 0; i < 30; i++)
{
a[i] = i + 1;
}
ans = 0;
dfs(0, 0, 0);
cout << ans << endl;
return 0;
}
2、实现最优性剪枝
#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<iostream>
#include<string>
using namespace std;
int n, m;//迷宫行列
string maze[110];
bool vis[110][110];//标记是否被访问
int dir[4][2] = { {-1,0},{0,-1},{1,0},{0,1} };
int ans = 100000;//先将ans设置为一个过大的数
bool in(int x, int y)
{
return 0 <= x && x < n && 0 <= y && y < m;//判断是否存在
}
void dfs(int x, int y, int step)//x,y为当前坐标,step为当前步数
{
//剪枝
if (step >= ans)
{
return;
}
if (maze[x][y] == 'T')
{
ans = step;
return;
}
vis[x][y] = 1;//先标记为访问过
for (int i = 0; i < 4; i++)
{
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if (in(tx, ty) && maze[tx][ty] != '*' && !vis[tx][ty])
{
dfs(tx, ty, step + 1);
}
}
vis[x][y] = 0;//搜索完后将标记清0,方便搜索到全部的路径
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i++)
{
cin >> maze[i];
}
int x, y;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (maze[i][j] == 'S')
{
x = i, y = j;
}
}
}
dfs(x, y, 0);
cout << ans << endl;
return 0;
}
3、重复性剪枝
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
int n, k, sum, ans;
int a[40];
bool xuan[40];
void dfs(int s, int cnt, int pos)
{
//剪枝
if (s > sum || cnt > k)
{
return;
}
if (s == sum && cnt == k)
{
ans++;
}
for (int i = pos; i < n; i++)
{
if (!xuan[i])
{
xuan[i] = 1;
dfs(s + a[i], cnt + 1, i + 1);
xuan[i] = 0;
}
}
}
int main()
{
n = 30;
k = 8;
sum = 200;
for (int i = 0; i < 30; i++)
{
a[i] = i + 1;
}
ans = 0;
dfs(0, 0, 0);
cout << ans << endl;
return 0;
}
4、奇偶性剪枝
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
const int N = 10;
int n, m, T;
char mat[N][N];
bool vis[N][N];//标记是否走过,因为走过的位置会坍塌,不能走多次
int dx[4] = { 0,0,-1,1 };
int dy[4] = { 1,-1,0,0 };
bool ok;//标记当前是否已经找到答案,如果为true就直接return,也是一种最优性剪枝
void dfs(int x, int y, int t)
{
if (ok)
{
return;
}
if (t == T)
{
if (mat[x][y] == 'D')
{
ok = true;
}
return;
}
vis[x][y] = true;
for (int i = 0; i < 4; i++)
{
int tx = x + dx[i];
int ty = y + dy[i];
if (tx < 0 || tx >= n || ty < 0 || ty >= m || mat[tx][ty] == 'X' || vis[tx][ty])
{
continue;
}
dfs(tx, ty, t + 1);
}
vis[x][y] = false;
}
int main()
{
cin >> n >> m >> T;
for (int i = 0; i < n; i++)
{
cin >> mat[i];
}
int sx, sy, ex, ey;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (mat[i][j] == 'S')
{
sx = i, sy = j;
}
if (mat[i][j] == 'D')
{
ex = i, ey = j;
}
}
}
if ((sx + sy + ex + ey + T) % 2 != 0)
{
cout << "NO" << endl;
}
else
{
ok = false;
dfs(sx, sy, 0);
if (ok)
{
cout << "YES" << endl;
}
else
{
cout << "NO" << endl;
}
}
return 0;
}
5、引爆炸弹
#define _crt_secure_no_warnings 1
#include<stdio.h>
#include<iostream>
using namespace std;
char mat[1010][1010];
int n, m;
bool row[1010], col[1010];
void boom(int x, int y)
{
mat[x][y] = 0;//表示访问过了
if (!row[x])
{
row[x] = true;
for (int i = 0; i < m; ++i)
{
if (mat[x][i] == '1')
{
boom(x, i);
}
}
}
if (!col[y])
{
col[y] = true;
for (int i = 0; i < n; ++i)
{
if (mat[i][y] == '1')
{
boom(i, y);
}
}
}
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; ++i)
{
cin >> mat[i];
}
int cnt = 0;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < m; ++j)
{
if (mat[i][j] == '1')
{
++cnt;
boom(i, j);
}
}
}
cout << cnt << endl;
return 0;
}
6、生日蛋糕
#define _CRT_SECURE_NO_WARNINGS 1
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<iostream>
using namespace std;
const int INF = 0x3f3f3f;
int n, m;
int ans;
int va[20];//最小体积和
void dfs(int u, int v, int s, int r0, int h0)//u为当前层数,v为当前体积,s为当前表面积,r0为该层圆柱体半径的上界,h0为该层圆柱体高的上界
{
if (u == m)
{
if (v == n)
{
ans = min(ans, s);
}
return;
}
if (va[m - u] + v > n)
{
return;
}
if (2.0 * (n - v) / r0 + s > ans)
{
return;
}
for (int r = r0; r >= m - u; r--)
{
for (int h = h0; h >= m - u; h--)
{
int tv = v + r * r * h;//当前体积
if (tv > n)
{
continue;//如果当前体积超过n,就不用继续搜索了,直接剪枝
}
int ts = s + 2 * r * h;//当前表面积
if (u == 0)
{
ts += r * r;//最底层的时候要加上顶部的面积
}
dfs(u + 1, tv, ts, r - 1, h - 1);
}
}
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
va[i] = va[i - 1] + i * i * i;
}
int r0 = sqrt(n) + 0.5;//加0.5是为了避免精度误差
ans = INF;
dfs(0, 0, 0, r0, n);
if (ans == INF)
{
ans = 0;
}
cout << ans << endl;
return 0;
}
7、找数字
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<cstdio>
using namespace std;
int n;
bool ok = false;
void dfs(long long x, int cnt)
{
if (cnt >= 19)
{
return;//递归出口1
}
if (ok)
{
return;//最优性剪枝,当已经找到了一种可行性解的时候就return
}
if (x % n == 0)
{
ok = true;//递归出口2
cout << x << endl;
return;
}
dfs(x * 10 + 0, cnt + 1);
//x*10+0 是在一个数字后面添加一个0,例如 12->120
dfs(x * 10 + 1, cnt + 1);
}
int main()
{
cin >> n;
dfs(1, 0);
return 0;
}
8、全排列
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<cstdio>
using namespace std;
int n;
bool vis[20];
void dfs(int cnt, int num)
{
if (cnt == n)
{
cout << num << endl;
return;//递归出口
}
for (int i = 1; i <= n; i++)//对每个数字进行尝试
{
if (!vis[i])
{
vis[i] = true;
dfs(cnt + 1, num * 10 + i);
vis[i] = false;
}
}
}
int main()
{
cin >> n;
int ans = 1;
for (int i = 1; i <= n; ++i)
{
//计算全排列的总方案数 n!
ans *= i;
}
cout << ans << endl;
dfs(0, 0);
return 0;
}
9、旅游计划
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int G[20][20];
bool vis[20];
int ans = 1000000000;
int n;
void dfs(int u, int cnt, int sum)
{
if (sum > ans)
{
return;//最优性剪枝
}
if (cnt == n)
{
ans = min(ans, sum + G[u][1]);
return;//递归出口
}
vis[u] = 1;
for (int i = 1; i <= n; ++i)//枚举当前城市可能到达的下一个城市
{
if (!vis[i])
{
dfs(i, cnt + 1, sum + G[u][i]);
}
}
vis[u] = 0;
}
int main()
{
cin >> n;
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= n; ++j)
{
cin >> G[i][j];
}
}
dfs(1, 1, 0);
cout << ans << endl;
return 0;
}
10、正方形
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<cstdio>
using namespace std;
int n;
int sum = 0;
int s1;
int le[4] = { 0 }, a[21], b[21] = { 0 };
bool ok = 0;
void dfs(int x, int j)
{
if (x == 4)
{
ok = 1;
return;//递归出口,已经搜索到了三条边
}
if (ok)
{
return;//最优性剪枝
}
if (le[x] > s1)
{
return;//可行性剪枝
}
if (le[x] == s1)
{
dfs(x + 1, 1);//已经搜索到一条边
}
else
{
for (int f = j; f <= n; ++f)//接着上次搜索的继续
{
if (b[f] == 0)
{
b[f] = 1;
le[x] += a[f];
dfs(x, f + 1);
le[x] -= a[f];
b[f] = 0;
}
}
}
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
sum += a[i];
}
s1 = sum / 4;
if (sum % 4 != 0)
{
cout << "No";
return 0;
}
dfs(1, 1);
if (ok)
{
cout << "Yes";
}
else
{
cout << "No";
}
return 0;
}
11、因数最多的数
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
typedef long long LL;//将long long类型重命名为LL
LL ans, mc, n;
const int prime[15] = { 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47 };
void dfs(int u, int m, LL x, LL cnt)
{
//u表示当前选择了多少个质因子,m表示当前的最高次,x表示当前的数,cnt表示当前数的因子个数
if (cnt > mc)
{
mc = cnt;
ans = x;
}
else if (cnt == mc && x < ans)
{
ans = x;
}
if (u == 15)
{
return;
}
for (int i = 1; i <= m; i++)
{
x = x * prime[u];
if (x > n)
{
break;
}
dfs(u + 1, i, x, cnt * (i + 1));
}
}
int main()
{
int T;
cin >> T;
while (T--)
{
cin >> n;
mc = 0;
dfs(0, 60, 1, 1);
cout << ans << endl;
}
return 0;
}
12、置换的玩笑
#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<iostream>
using namespace std;
string s;
int ans[100];
int n;
bool vis[100];
bool ok;
void dfs(int u, int cnt)
{
//u表示当前考虑到了字符串的哪一位,cnt表示分出来多少个数
if (ok)
{
return;
}
if (u == s.size())
{
for (int i = 0; i < cnt; i++)
{
cout << ans[i] << " ";
}
cout << endl;
ok = true;
return;
}
int x = s[u] - '0';//拆出一位来
if (x <= n && !vis[x])
{
ans[cnt] = x;
vis[x] = true;
dfs(u + 1, cnt + 1);
vis[x] = false;
}
if (u + 1 >= s.size())
{
return;
}
x = x * 10 + s[u + 1] - '0';
if (x <= n && !vis[x])
{
ans[cnt] = x;
vis[x] = true;
dfs(u + 2, cnt + 1);
vis[x] = false;
}
}
int main()
{
cin >> s;
n = s.size() <= 9 ? s.size() : (s.size() - 9) / 2 + 9;//三目运算符,若问号前语句为true,则返回冒号前的值,否则返回冒号后的值
//若小于9则为一位数,直接返回字符串长度即可,若大于9,则减去一位数的个数,再除以二算出两位数的个数,再加上一位数的个数为总共的个数
dfs(0, 0);
return 0;
}