题目1——烤鸡
题目描述
题解
这是一个简单的暴搜题目,由于一共由10种配料,每种配料可以放1到3克,因此只需要用dfs
对每种配料放入的质量进行暴力搜索即可,如果放入的配料质量之和等于题目给出的美味程度 n n n,记录一下,最终将所有得到的符合题目要求的答案输出一遍。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;int n;
int res[N][10];
int temp[10];
int idx;void dfs(int u, int sum)
{if(u == 10){if(sum == n){for(int i = 0; i < 10; i ++)res[idx][i] = temp[i];idx ++;}return ;}// 枚举for(int i = 1; i <= 3; i ++){// 选择itemp[u] = i;dfs(u + 1, sum + i);}
}
int main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin>>n;dfs(0, 0);if(idx){cout<<idx<<'\n';for(int i = 0; i < idx; i ++){for(int j = 0; j < 10; j ++)cout<<res[i][j]<<' ';cout<<'\n';}}else{cout<<"0"<<'\n';}return 0;
}
题目2——外星人
题目描述
题解
乍一看题目感觉很复杂,但看了样例手动模拟了一下之后发现就是简单的排列组合,即给定一组数(输入的第三行),从这组数开始,按照从小到大(数字的大小)进行全排列第 M M M次后的结果。
题目样例
1 2 3 4 5 —— 原始序列
1 2 3 5 4 —— 第一次排列得到的序列
1 2 4 3 5 —— 第二次排列得到的序列
1 2 4 5 3 —— 第三次排列得到的序列( M = 3 M = 3 M=3)
也就是说,我们以给定的初始序列为起点,使用dfs
进行全排列,排列到第 M M M次的时候输出答案,退出即可
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;int n, m, num; //num记录第几次
int figure[N];
int temp[N];
bitset<N> bt;void dfs(int u)
{// 找到一种排列if(u == n){num ++;if(num == m + 1) // 第一次找到排序是原始序列 因此要找m+1次{for(int i = 0; i < n; i ++)cout<<temp[i]<<' ';exit(0);}return ;}for(int i = 1; i <= n; i ++){if(num == 0) i = figure[u]; // 从指定位置开始搜索if(!bt[i]){bt[i] = true;temp[u] = i;dfs(u + 1);// 恢复现场bt[i] = false;}}
}
int main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin>>n>>m;for(int i = 0; i < n; i ++) cin>>figure[i];dfs(0);return 0;
}
题目3——火柴棒等式
题目描述
题解
首先阅读题目,总的来说就是找到A
、B
、C
三个数字,要求满足:
- A + B = C A + B = C A+B=C
- 三个数字使用的火柴棒总数为
n - 4
(加号和等号一共要消耗4个火柴棒)
对于这种题目,我们可以对每个位置(A、B、C
一种三个位置)上可以选择的数字进行爆搜,每次搜索完之后检查找到的三个数字是否满足以上的两个条件
由于A
、B
、C
可能会为两位数或者三位数,因此我们还要开一个数组(dic
)来维护每个数字需要多少根火柴棒,这里我使用了记忆搜索的思想,即如果dic[x]
(x
为数字)在之前使用过,则记录下来;如果没使用过,则计算后再保存下来,方便下次调用时使用。具体代码如下所示:
int dic[1005] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
int cal(int x)
{if(dic[x] > 0) return dic[x];int sum = 0, t = x;
// cout<<t<<'\n';while(x){sum += dic[x % 10];x /= 10;}dic[t] = sum;return sum;
}
整体代码
#include<bits/stdc++.h>
using namespace std;
const int N = 30;int n;
int dic[1005] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
int temp[N];
int res;int cal(int x)
{if(dic[x] > 0) return dic[x];int sum = 0, t = x;
// cout<<t<<'\n';while(x){sum += dic[x % 10];x /= 10;}dic[t] = sum;return sum;
}
void dfs(int u, int sum)
{if(sum > n) return ;if(u == 3){if((temp[0] + temp[1] == temp[2]) && sum == n)res ++;return ;}for(int i = 0; i <= 1000; i ++){temp[u] = i; // 第u个位置选择idfs(u + 1, sum + cal(i));}
}
int main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n; n -= 4;dfs(0, 0);cout<<res;return 0;
}
题目4——PERKET
题目描述
题解
这道题目也比较简单,是一种指数类问题,即大致思路就是对每一种配料选和不选进行暴力搜索,最后维护一下最小的酸度和苦度的绝对值即可。
注意由于题目所述必须至少添加一种配料,因此每次枚举完所有的配料选择方案时,要加一个判断,把一种配料都不选的方案筛掉。
代码
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 20;ll n;
ll s[N], b[N];
int bt[N];
ll res = 1e9;void dfs(int u)
{if(u == n){int sum = 0;for(int i = 0; i < n; i ++) sum += bt[i];if(sum == 0) return; // 一种材料都没选ll ss = 1, bb = 0;for(int i = 0; i < n; i ++){if(bt[i]) ss *= s[i];bb += bt[i] * b[i];}res = min(res, abs(ss - bb));return ;}// 选择第u种材料bt[u] = 1;dfs(u + 1);// 不选择第u种材料bt[u] = 0; //恢复现场dfs(u + 1);
}int main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin>>n;for(int i = 0; i < n; i ++){cin>>s[i]; cin>>b[i];}dfs(0);cout<<res;return 0;
}
题目5——奇怪的电梯
题目描述
题解
这道题刚上来觉得很复杂,但仔细想了一下之后,就是一个简单的dfs
,从楼层a
开始,分别搜索上行和下行两种方案,最终看能不能到达楼层b
,注意不要忘记判断楼层是否合法
!!!但是这样会TLE
于是后来我进行了优化(参考洛谷题解里的大佬hhh),即使用一个数组去维护从楼层a
开始,到当前楼层的最短距离,根据这个数组进行剪枝。举个例子:
假如我们第一次到达楼层
c
,此时按按钮的次数为3,由于这是第一次到达楼层c
,因此我们把这个数字记录下来;
而当我们再后续搜索时,再次到达了楼层c
,按按钮的次数为9,因为9 > 3
,肯定得不到最优解,因此剪枝
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 210;int n, a, b;
int k[N], dic[N];
int res = 0x3f3f3f3f;// u代表当前是第几层 num 是按电梯次数
void dfs(int u, int num)
{// 越界if(u > n || u <= 0) return ;// 不是最优if(num >= dic[u]) return ;else dic[u] = num;if(num > res) return ;// resif(u == b){res = min(res, dic[u]);}// 向上dfs(u + k[u], num + 1);// 向下dfs(u - k[u], num + 1);return ;
}
int main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin>>n>>a>>b;for(int i = 1; i <= n; i ++) cin>>k[i];memset(dic, 0x3f, sizeof(dic));dfs(a, 0); // 从a楼开始if(res == 0x3f3f3f3f) cout<<"-1"<<'\n';else cout<<res;return 0;
}