两人分糖果问题

题目描述:小明和小红是好朋友,但最近遇到一个棘手的问题,有一盒糖果要分成两份但是每颗糖果质量都不尽相同,但为了分配的公平每份糖的糖果数量相差不得超过1,在此条件下两份糖果的质量差距尽可能小。

输入:一行数,包含一个数n,代表糖果数量,后面一次是n个整数一次表示每个糖果的质量,每个糖果的质量都是1到450之间的一个整数,每盒最多有20个糖果。

输出:每个样例输出两个数字分别为两堆糖果的质量,如不相同,先小后大。

样例

输入:5 9 6 5 8 7

输出:17 18
分析:
  1. 要求2人分得质量差距最小,则2人分得质量应该在所有糖果质量一半附近,且其中一人所得质量与总质量一半的差距应该是所有分配方法中最小的。
  2. 要求2人分得糖果数量相差不超过1,无论糖果总数n是奇数还是偶数,其中一人总会分得n/2个糖果。
思路:对每个糖果采用取或者不取的态度,随机从n个糖果中取得n/2个糖果,计算得到所有C(n,n/2)种分配方式,所得分配方式中与总质量一半相差最小的即为答案。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int Min = INT_MAX;
int num;//糖果数量的一半,数量为奇数时,取下限。
int sum = 0;//所有糖果的质量
int res;

void devide(vector<int> candy, int w, int start, int cnt) {//w:目前已分得质量
	if (cnt == num) {//数量达到条件
		if (abs(w * 2 - sum) < Min) {//保存暂时最好结果
			res = w;
			Min = abs(w * 2 - sum);
		}
	}
	else {
		if (start == candy.size())return;//start从0开始,达到candy.size()说明已越界,结束递归。
		devide(candy, w, start + 1, cnt);//这颗糖果不取
		devide(candy, w + candy[start], start + 1, cnt + 1);//这颗糖果取。
	}
}
int main() {
	int n;
	cin >> n;
	vector<int> candy(n);
	for (int i = 0;i < n;i++) {
		cin >> candy[i];
		sum += candy[i];
	}
	num = n / 2;
	devide(candy, 0, 0, 0);
	if (res * 2 > sum) 
		cout << sum - res << " " << res << endl;
	else 
		cout << res << " " << sum - res << endl;
	return 0;
	

}

### C++ 实现糖果问题 以下是基于引用内容和常见逻辑设计的一个通用解决方案,用于解决不同场景下的糖果问题。 #### 场景一:圆桌上的小朋友糖果 此场景下,每个小朋友将自己的糖果成三份并传递给邻居。代码如下: ```cpp #include <iostream> using namespace std; int main() { int a, b, c, d, e; cin >> a >> b >> c >> d >> e; // 小朋友依次操作 a = a / 3; b += a; e += a; // 第1位小朋友的操作 b = b / 3; c += b; a += b; // 第2位小朋友的操作 c = c / 3; d += c; b += c; // 第3位小朋友的操作 d = d / 3; e += d; c += d; // 第4位小朋友的操作 e = e / 3; a += e; d += e; // 第5位小朋友的操作 cout << a << " " << b << " " << c << " " << d << " " << e; return 0; } ``` 上述代码实现了每位小朋友按照规则糖果的过程[^1]。 --- #### 场景二:通过循环动态输入糖果数量 当需要处理不确定数量的小朋友时,可以采用 `vector` 动态存储数据,并利用循环完成配过程。代码如下: ```cpp #include <iostream> #include <vector> using namespace std; int main() { cout << "输入一个得数组:" << endl; vector<int> candies; int input; // 使用 do-while 循环读取输入直到遇到换行符 do { cin >> input; candies.push_back(input); } while (getchar() != '\n'); // 假设每个都将糖果为三部 for (size_t i = 0; i < candies.size(); ++i) { int current = candies[i]; int share = current / 3; // 更新当前小朋友及其邻居的糖果数量 candies[i] -= 2 * share; if (i > 0) candies[(i - 1) % candies.size()] += share; candies[(i + 1) % candies.size()] += share; } // 输出最终结果 for (const auto& candy : candies) { cout << candy << " "; } return 0; } ``` 该代码扩展了固定数的情况至任意数的情形[^2]。 --- #### 场景三:判断区间内的最大可得糖果数 对于特定范围 `[L, R]` 的糖果袋子,计算能够获得的最大糖果数目。代码如下: ```cpp #include <bits/stdc++.h> using namespace std; int main(){ int n, L, R; cin >> n >> L >> R; if(L / n < R / n){ cout << n - 1; // 如果[L,R]包含至少一组完整的n,则最多能拿n-1个 } else{ cout << R % n; // 否则尽可能多地拿剩余的部 } return 0; } ``` 这段程序解决了如何在指定范围内最大化获取糖果数量问题[^3]。 --- #### 场景四:公平糖果 假设有一组糖果袋,目标是将其平等地配给位玩家。如果无法做到平等配,则返回 `-1`。代码如下: ```cpp #include <iostream> #include <vector> using namespace std; pair<vector<int>, vector<int>> distributeCandies(const vector<int>& bags) { long totalSum = 0; for(auto bag : bags) totalSum += bag; if(totalSum % 2 != 0) return {{}, {}}; long target = totalSum / 2; vector<bool> dp(target + 1, false); dp[0] = true; vector<int> subsetA, subsetB; for(int num : bags){ for(long j=target; j>=num && !dp[target]; --j){ if(dp[j-num]){ dp[j]=true; break; } } } if(!dp[target]) return {{}, {}}; bool flag=true; for(int k=bags.size()-1;k>=0&&target>0;--k){ if(flag && dp[target-bags[k]]){ subsetA.emplace_back(bags[k]); target-=bags[k]; } else{ subsetB.emplace_back(bags[k]); } } return {subsetA, subsetB}; } int main(){ int N; cin >> N; vector<int> bags(N); for(auto &bag:bags) cin>>bag; pair<vector<int>, vector<int>> result = distributeCandies(bags); if(result.first.empty()){ cout<< "-1"; } else{ cout<<accumulate(result.first.begin(),result.first.end(),0)<<endl; for(auto val:result.first) cout<<val<<" ";cout<<"\n"; for(auto val:result.second) cout<<val<<" ";cout<<"\n"; } return 0; } ``` 以上代码展示了如何实现之间的公平糖果配[^4]。 --- ### 总结 根据不同需求,提供了四种典型场景下的 C++ 糖果算法实现方案。每种方法都针对具体条件进行了优化调整。 相关问题
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值