前言
本文记录4月13日晚7点一场软件开发岗笔试的题目,思路以及代码实现。
一、题目简介
题目:
分糖果
具体描述:
给俩人分糖果,每袋糖果中的糖果数量不完全一致,一袋糖果只能分给一个人且必须全部分完,两个人分到的糖果数量必须相同,返回两人分到的糖果数量,如果无法平均分配则返回-1。
输入输出:
输入:
第一行输入糖果袋数。
第二行输入为一个整型数组,描述每袋糖果中的糖果数量。
输出:
第一行为每人平均分配到的糖果数,如果不能平均分配则为-1。
第二行、第三行为两个人分配到的每袋糖果中的糖果数,顺序不限。
二、思路
这个题目很短,很好理解,仔细研究发现是个01背包问题,但是一写才发现并不简单,因为一般的DP问题只要求输出一个结果,但本题需要输出路径,各种改造01背包搞了半天也没撕出来,主要问题还是缺少经验,方向没弄对,这题我看压根不能用DP做,不知道咋用DP存储路径。这个题考察的其实还是DFS和回溯,详情参考leetcode40,思路一致。最后因为这个题要分成两堆,想不出找到一堆之后另一堆怎么找,于是弄了个pair把下标也存起来,实现起来还是比较麻烦的。
三、C++代码实现
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
int n;
bool flag;
vector<int> _nums;
vector<pair<int, int>> nums; // 输入的一堆数和每个数的下标
vector<vector<pair<int, int>>> plans; // 第一堆的所有方案
vector<pair<int, int>> part; // 分成两堆数后其中的一堆数(数和下标)
void dfs(vector<pair<int, int>> nums, int u, int target)
{
if (target == 0)
{
flag = true;
plans.push_back(part);
return;
}
if (u == nums.size()) return;
int k = u;
while (k < nums.size() && nums[k].first == nums[u].first) k++;
int cnt = k - u;
for (int i = 0; i <= cnt && i * nums[u].first <= target; i++)
{
dfs(nums, k, target - i * nums[u].first);
part.push_back(nums[u]);
}
for (int i = 0; i <= cnt && i * nums[u].first <= target; i++)
{
part.pop_back();
}
}
int main()
{
cin >> n;
int sum = 0;
for (int i = 0; i < n; i++)
{
int x;
cin >> x;
_nums.push_back(x);
sum += x;
}
if (sum % 2 != 0) cout << -1 << endl; // 所有数总和为奇数,直接G
else
{
int target = sum / 2;
sort(_nums.begin(), _nums.end());
for (int i = 0; i < _nums.size(); i++) nums.push_back(make_pair(_nums[i], i)); // 使用pair维护每个数的值和其下标
dfs(nums, 0, target);
if (!flag) cout << -1 << endl; // 无法平均分配
else
{
part = plans[0]; // 取第一套方案作为第一堆的数即可
vector<int> res1; // 存第一堆中每个数在nums中的下标
vector<int> res2; // 存第二堆中每个数在nums中的下标
for (int i = 0; i < part.size(); i++) res1.push_back(part[i].second); // 第一堆数的下标
for (int i = 0; i < nums.size(); i++)
{
if (count(res1.begin(), res1.end(), i) == 0) // 遍历nums,只要下标没在res1中,那这个下标就放到res2中
res2.push_back(i);
}
string nums_1;
for (int i = 0; i < res1.size(); i++)
{
nums_1 += to_string(nums[res1[i]].first) + " ";
}
nums_1 = nums_1.substr(0, nums_1.size() - 1);
string nums_2;
for (int i = 0; i < res2.size(); i++)
{
nums_2 += to_string(nums[res2[i]].first) + " ";
}
nums_2 = nums_2.substr(0, nums_2.size() - 1);
cout << target << endl;
cout << nums_1 << endl;
cout << nums_2 << endl;
}
}
return 0;
}
总结
结论:以后看到要输出路径的,先不考虑DP,先看DFS能不能做。
冲鸭!