当前位置 博文首页 > William_Chan_6的博客:【c++】大疆笔试题,应该怎么吃呢
题目如下:
时间限制:C/C++语言1000Ms;其他语言3000 Ms
内存限制:C/C+语言65536KB;其他语言589824KB
题目描述:
小W非常喜欢吃零食,经常都会去零食间里购买半价的零食吃,但是他为了控制自己的体重,因此会限制自己买零食的开销在某个数值以内。
但是小W有一个特别的爱好,他对于某些零食特别的喜欢,并且会对这些零食的喜爱程度进行排序。对于零食A和零食B,如果小W对零食A的喜爱程度大于对零食B的喜爱程度,那么每次拿零食的时候,一定会确保A的数目比B多。
现在零食间里有N种零食,假设每种零食都是取不完的,但小W每次都会刚好花完所有的开销,那么小W去取零食的时候应该有多少种可能的取法呢?
输入
输入包含多组测试数据,每组数组:
第一行:买零食的开销V(V<1000和所有的零食种类数目N(N<200)
第二行:第i个正整数表示第i种零食的价格ci(ci<1000)
第三行:特别喜欢的零食的种类数M(2<=M<=N)
第四行:按照对M种零食的喜爱程度从高到低排序,第i种零食的喜爱程度会大于第i+1种,保证不会形成环
输出
对于每组测试数据
输出一个整数ans,表示在满足小W的特殊偏好的情况下,并且花光所有开销,有多少可能方案。由于ans可能很大,因此最终结果ans%100000
下面是暴力穷举法的代码,笔者才浅,没想到特别好的算法来解决这个问题,如果有更好的算法,希望能在评论区指出,多谢! 刷了一阵leetcode,实现了另一种解法,见后文。
//暴力穷举法
#include <iostream>
#include <vector>
using namespace std;
int result_num = 0;
//打印vector
template <typename T>
void print_vector(vector<T> vec) {
cout << '[';
//遍历输出,空格间隔
for (auto i = vec.begin(); i != vec.end(); i++) {
if (i + 1 == vec.end())
cout << *i << ']' << endl;
else
cout << *i << " ";
}
}
//计算方案result所需花销
int cal_cost(const vector<int>& results, const vector<int>& costs) {
int cost = 0;
for (size_t i = 0; i < results.size(); i++)
{
cost += results[i] * costs[i];
}
return cost;
}
//判断方案results花销够不够
bool cost_enough(int all_cost, const vector<int>& results, const vector<int>& costs) {
return all_cost >= cal_cost(results, costs);
}
//判断方案是否可行
bool good_result(int all_cost, const vector<int>& results, const vector<int>& costs) {
return all_cost == cal_cost(results, costs);
}
//判断喜爱程度是否满足要求
bool good_favor(const vector<int>& results, const vector<int>& favors) {
//遍历favors
for (int i = 0; i < favors.size() - 1; i++) {
//如果后一个零食个数不为0
if (results[favors[i + 1]] != 0) {
if (results[favors[i]] <= results[favors[i + 1]])
return false;
}
}
return true;
}
//暴力穷举,
void solve(int all_cost, int ope_index, const vector<int>& costs, const vector<int>& favors, vector<int>& results) {
//只要花销够,就继续循环
while (cost_enough(all_cost, results, costs)) {
//如果花销刚好花完
if (good_result(all_cost, results, costs)) {
//如果满足喜爱程度要求,则解+1
if (good_favor(results, favors)) {
result_num++;
print_vector<int>(results);
}
//返回上级
results[ope_index] = 0;
return;
}
//不拿当前零食
//如果不是最后一个零食,处理下一个零食
if (ope_index + 1 < costs.size())
solve(all_cost, ope_index + 1, costs, favors, results);
else
{
//剩余开销
int left_cost = all_cost - cal_cost(results, costs);
//如果刚好用完,且满足要求,解+1
if (left_cost%costs[ope_index] == 0 && good_favor(results, favors)) {
results[ope_index] = left_cost / costs[ope_index];
result_num++;
print_vector<int>(results);
}
//返回上级
results[ope_index] = 0;
return;
}
//拿当前零食,继续循环
results[ope_index]++;
}
//如果花销不够,当前拿取数清零,返回上级
results[ope_index] = 0;
return;
}
int main()
{
//输入
int case_num;//案例数
cin >> case_num;
for (int c = 0; c < case_num; c++) {
int all_cost, snack_num;//总开销,零食种类数
int favor_num;//喜爱零食的数量
vector<int> costs;//开销列表
vector<int> favors;//喜爱程度列表,越靠前越喜
cin >> all_cost >> snack_num;
for (int i = 0; i < snack_num; i++) {
int cost;
cin >> cost;
costs.push_back(cost);
}
cin >> favor_num;
for (int i = 0; i < favor_num; i++) {
int snack;
cin >> snack;
favors.push_back(snack);
}
//暴力穷举
vector<int> results;
for (size_t i = 0; i < costs.size(); i++)
{
results.push_back(0);
}
solve(all_cost, 0, costs, favors, results);
//打印结果
cout << "result number:" << result_num % 100000 << endl;
//结果清零
result_num = 0;
}
}
/*
input:
2
10 3
4 5 6
2
0 1
20 5
2 4 5 6 7
2
1 2
*/
运行结果
解法2,深度优先遍历,分两个数组,一个存储有优先级的零食,优先级越高的零食越靠前,另一个存储无优先级的零食。
代码主体如下:
class Solution {
const static bool debug = false;
const static int mod = 100000;
int C, n, m, ans = 0;
//nums0中有优先级,nums1中无
vector<int> nums0, nums1;
//对nums1处理
void dfs1(int i, int cost) {
if (debug)
cout << "dfs1 i=" << i << " cost=" << cost << endl;
if (cost == C) {
++ans;
if (debug)
printf("update ------------- ans:%d --------------- \n", ans);
}
else if (cost > C || i >= nums1.size())
return;
else {
for (int count = 0; cost + count * nums1[i] <= C; count++)
dfs1(i + 1, cost + count * nums1[i]);
}
}
//拿不拿第i个,当前消费为cost
void dfs(int i, int cost, int lastCount) {
if (debug)
cout << "dfs i=" << i << " cost=" << cost << " lastCount=" << lastCount << endl;
//越界
if (cost > C)
return;
//nums0拿完之后,开始拿nums1
if (i == nums0.size())
dfs1(0, cost);
//出口
else if (cost == C) {
++ans;
if (debug)
printf("update ------------- ans:%d --------------- \n", ans);
}
//递归
else {
//拿i的个数小于lastCount
for (int count = 0; count < lastCount
&& cost + count * nums0[i] <= C; count++)
dfs(i + 1, cost + count * nums0[i], count);
}
}
public:
Solution(int c) {
C = c;
cin >> n;
vector<int> nums;
int temp;
for (int i = 0; i < n; i++){
cin >> temp;
nums.push_back(temp);
}
cin >> m;
for (int i = 0; i < m; i++){
cin >> temp;
nums0.push_back(nums[temp]);
nums[temp] = -1;
}
for (int num : nums)
if (num != -1)
nums1.push_back(num);
}
void solve() {
//不拿nums0
dfs1(0, 0);
//先拿nums0再拿nums1
dfs(0, 0, INT_MAX);
cout << ans % mod << endl;
}
};
int main() {
int c;
while (cin >> c) {
Solution s(c);
s.solve();
}
return 0;
}
测试上述样例,结果相同
cs