分糖果算法题-C++实现

前言

本文记录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能不能做。
冲鸭!

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
第1篇 编程基础 第1章 开发环境 1.1 工程创建 实例001如何创建基于对话框的MFC工程 实例002如何创建基于文档视图的MFC工程, 实例003打开已存在的工程 实例004怎样查找工程中的信息 实例005怎样在添加对话框资源时创建对话框类 实例006在工作区中管理多个工程 实例007创建MFCActiveX工程 实例008创建ATL工程 实例009创建控制台应用程序 1.2 开发环境设置与使用 实例010怎样定制自己的工具栏 实例011在VC项目中使用自定义资源 实例012向VisualC++开发环境中添加插件 实例013添加消息处理函数 实例014设置开发环境文本颜色 实例015设置批量注释 实例016如何对齐零乱的代码 实例017判断代码中的括号是否匹配 实例018修改可执行文件中的资源 1.3 程序调试 实例019创建调试程序 实例020在Release版本中进行调试 实例021在vc中如何进行远程调试 实例022利用简单断点进行程序调试 实例023利月条件断点进行程序调试 实例024利用数据断点进行程序调试 实例025利用消息断点进行程序调试 实例026利用Watch调试窗口查看对象信息 实例027利用CallStack窗口查看函数调用信息 实例028利用Memory窗口查看内存信息 实例029利用Variables窗口查看变量信息 实例030利用Registers窗口查看CPU寄存器信息 实例031利用Disassembly窗口查看汇编信息 第2章 语言基础 2.1 基本语法 实例032输出问候语 实例033输出带边框的问候语 实例034不同类型数据的输出 实例035输出字符表情, 实例036获取用户输入的用户名 2.2 运算符的妙用 实例037简单的字符加密 实例038实现两个变量的互换 实例039判断性别 实例040用宏定义实现值互换 实例041简单的位运算 实例042整数加减法练习 2.3 条件语句 实例043李白喝酒问 实例044桃园三结义 实例045何年是闰年 实例046小球称重 实例047购物街中的商品价格竞猜 实例048促销商品的折扣计算 实例049利用switch语句输出倒三角形 2.4 循环语句 实例050PK少年高斯 实例051灯塔数量 实例052上帝创世的秘密 实例053小球下落 实例054再现乘法口诀表 实例055判断名次 2.5 循环的数学应用 实例056序列求和 实例057简单的级数运算 实例058求一个正整数的所有因子 实例059一元钱兑换方案 2.6 趣味计算 实例060加油站加油 实例061买苹果问 实例062猴子吃桃 实例063老师分糖果 实例064新同学的年龄 实例065百钱买百鸡问 实例066彩球问 实例067集邮册中的邮票数量 2.7 多重循环打印图形 实例068用打印三角形 实例069用叶印图形 实例070绘制余弦曲线 实例071打印杨辉三角 2.8 算法 实例072计算某日是该年第几天 实例073斐波那契数列 实例074角谷猜想 实例075哥德巴赫猜想 实例076四方定理 实例077尼科彻斯定理 实例078魔术师的秘密

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值