当前位置 博文首页 > William_Chan_6的博客:【c++】大疆笔试题,应该怎么吃呢

    William_Chan_6的博客:【c++】大疆笔试题,应该怎么吃呢

    作者:[db:作者] 时间:2021-08-22 21:17

    题目如下:

    时间限制: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