题目如下:
时间限制:CC++语言1000Ms;其他语言3000 Ms
内存限制:CC+语言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种零食的喜爱程度会大于第计+1种,保证不会形成环
输出
对于每组测试数据
输出一个整数as,表示在满足小W的特殊偏好的情况下,并且花光所有开销,有多少可能方案。由于ansi可能很大,因此最终结果ansi%100000
下面是暴力穷举法的代码,笔者才浅,没想到特别好的算法来解决这个问题,如果有更好的算法,希望能在评论区指出,多谢!
#include
#include
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
*/
运行结果