[C++] 2017联发科技杯编程挑战赛 复赛题 “杰克船长的烦恼”



题目如下。

规则

杰克船长这次运气不错,抢到了一大堆金币。但他马上又开始发愁了, 因为如何给大家分金币,一直都是件不容易的事,每次杰克船长都要头疼好几天。

关于分金币,海盗的行规是这样的:

  • 每次行动,船长会根据各个海盗的表现记功,事后论功行赏,给大家分金币。
  • 分战利品的时候,海盗们会随意的站成一排,船长给每个人发一袋金币。袋子里的金币数目有多有少,但船长保证每个海盗至少会分到一枚金币。
  • 拿到金币后,相邻的两个海盗会互相比较。如果其中一个功劳高些,那他的金币必须多一些,如果两个人分数一样,他们的金币必须一样。否则,海盗们就觉得不公平,要闹事,甚至造反。

怎么样才能用最少的金币让大家都满意呢? 领导这帮海盗可不轻松。

听说这次比赛中有一位将来要成为海贼王的男人,杰克船长相信他一定能解决这个麻烦。

输入说明

在程序当前目录下存在execute.stdin文件,程序从execute.stdin中取得输入数据。

execute.stdin中存放着N(N<100)个十进制正整数,数字之间用空格格开。

每个数字都代表某个海盗的功劳,值范围为(1, 100)。

输出说明

输出一个正整数,代表让所有海盗都满意的最少的金币数。

算法思路

  • 找出序列中所有的局部最小值,给对应位置的船员分配一枚金币,然后两侧的依次金币数加1。
  • 在两个局部最小值之间有一个局部最大值,例如一段序列... 11 12 13 14 12 11 ... ,若两侧的11是局部最小值,14是局部最大值,则从左往右,11到13的位置分别分配1 2 3枚金币;从右往左,11到12的位置分别分配1 2枚金币,14的位置如果分配3枚金币的话不能满足比13多的条件,所以14的位置分配4个金币。所以,从两侧的局部最小值依次递增到局部最大值位置的时候,局部最大值对应位置取较大的金币数。
  • 对于序列的最左和最右位置,如果第一个数小于/大于第二个数,则其是局部最小/大值;如果最后一个数小于/大于倒数第二个数,则其是局部最小/大值;

源代码

#include <iostream>
#include <fstream>
#include <vector>

using std::vector;
// vector作为函数参数和返回值表示法
void money(const vector <int> & value);
vector <int> findLocalMin(const vector <int> & vec);

int main()
{
    /*打开文件,获取功劳值信息*/
    std::ifstream file;
    file.open("execute.stdin");

    int temp;
    vector <int> value;  // 存储功劳值

    if (!file)
    {
        std::cout << "Error!";
    }
    while (file >> temp)
    {
        value.push_back(temp);
    }
    file.close();

    /*计算金币数*/
    money(value);

    //std::cin.get();
    return 0;
}

void money(const vector <int> &value)
{

    // 去除重复的数
    int length = value.size();
    vector <int> newValue;

    newValue.push_back(value[0]);
    for (int i = 1; i < length; ++i)
    {
        if (value[i] != value[i - 1])
        {
            newValue.push_back(value[i]);  // 抽取不重复的数
        }
    }

    // 找局部最小值位置
    vector <int> minLocalPos = findLocalMin(newValue);

    // 分配金币(对应不重复的序列)

    int len = newValue.size();
    vector <int> gold;  // 放置金币(对应原始序列)
    vector <int> newGold(len, 1);  // 放置金币(对应不重复的序列)

    if (minLocalPos[0] > 0)  // 刚开始是递减
    {
        for (int k = minLocalPos[0] - 1; k >= 0; --k)
        {
            newGold[k] = newGold[k+1] + 1;  // 在后一个的基础上加一
        }
    }

    for (int i = 1; i < minLocalPos.size(); ++i)
    {
        for (int j = minLocalPos[i - 1] + 1; j < minLocalPos[i]; ++j)  //从前往后
        {
            if (newValue[j] > newValue[j - 1])
            {
                newGold[j] = newGold[j-1] + 1;  // 在前一个的基础上加一
            }
        }
        for (int j = minLocalPos[i] - 1; j > minLocalPos[i - 1]; --j)  //从后往前
        {
            // 如果此方向的梯度更大
            if ((newValue[j] > newValue[j + 1]) && (newGold[j + 1]+1 > newGold[j]))
            {
                newGold[j] = newGold[j + 1] + 1;  // 在后一个的基础上加一
            }
        }
    }

    int end = minLocalPos[minLocalPos.size() - 1];
    if (len - 1 > end)  // 末尾是单调增的
    {
        for (int i = end + 1; i < len; ++i)
        {
            newGold[i] = newGold[i - 1] + 1;  // 在前一个的基础上加一
        }
    }

    /*for (int k = 0; k < newGold.size(); ++k)
    {
        std::cout << newGold[k] << " ";
    }*/

    // 分配金币(对应原始的value序列)
    int j = 0;
    int i = 0;
    while(i < length)
    {
        if (value[i] == newValue[j])
        {
            gold.push_back(newGold[j]);
            ++i;
        }
        else
        {
            ++j;
        }
    }

    // 计算金币和
    int sum = 0;
    for (int k = 0; k < gold.size(); ++k)
    {
        //std::cout << gold[k] << " ";
        sum += gold[k];
    }
    std::cout << sum;
}

// 找局部最小值的位置
vector <int> findLocalMin(const vector <int> & vec)
{
    vector <int> minLocalPos;
    int len = vec.size();

    if (len == 1)
    {
        minLocalPos.push_back(0);
        return minLocalPos;
    }

    // len >= 2
    if (vec[0] < vec[1])
    {
        minLocalPos.push_back(0);
    }

    for (int i = 1; i < len - 1; ++i)
    {
        if ((vec[i] < vec[i - 1]) && (vec[i] < vec[i + 1]))
        {
            minLocalPos.push_back(i);
        }

    }

    if (vec[len - 1] < vec[len - 2])
    {
        minLocalPos.push_back(len - 1);
    }

    return minLocalPos;
}

运行结果

原文地址:https://www.cnblogs.com/Ran-Chen/p/9390040.html

时间: 2024-11-05 17:26:52

[C++] 2017联发科技杯编程挑战赛 复赛题 “杰克船长的烦恼”的相关文章

2018“氢舞杯”编程挑战赛

问题 F: 最小重量机器设计问题 时间限制: 1Sec 内存限制: 128MB 提交: 115 解决: 0 题目描述 设某一机器由n个部件组成,每一种部件都可以从m个不同的供应商处购得.设Wij 是 从供应商j处购得的部件i的重量,Cij 是相应的价格. 试设计一个算法,给出总价格不超过c的最小重量机器设计. ′编程任务: 对于给定的机器部件重量和机器部件价格,编程计算总价格不超过d的最小重量机器设 计. 输入 第一行有 3 个正整数 n ,m和 d.接下来的 2n 行,每 行m个数.前n行是c

2018“氢舞杯”编程挑战赛2

问题 N: 逆反的01串 时间限制: 1Sec 内存限制: 128MB 提交: 10 解决: 7 题目描述 Fans是个ACM程序设计迷.有时侯,他表现出很强烈的逆反心理,你往东,他往西,你往南,他偏往北.这一次,不知道又是谁惹着他了,好端端的一个个01串,到了他的手里,都变成10串了.请你编个程序来模仿他的行为,将01串(长度≤200),全变成10串吧. 输入 0110100100100 1000000010000000000 输出 1001011011011 0111111101111111

hdu 4542 数论 + 约数个数相关 腾讯编程马拉松复赛

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4542 小明系列故事--未知剩余系 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 889    Accepted Submission(s): 207 Problem Description "今有物不知其数,三三数之有二,五五数之有三,七七数之有

2017盛大游戏杯 零件组装(状态压缩DP之巧妙枚举子集)

题目链接:2017盛大游戏杯 零件组装 题意: 有n个零件,给你相邻关系和排斥关系,每两块零件组装起来有一个代价,问最少的代价总和是多少. 题解: 考虑状态压缩,dp[i]表示i这个集合为一个零件块. 那么要枚举一下i的子集.O(3^n). 先要预处理一下每个集合的排斥个数和相邻个数,然后容斥一下就可以了. 1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int

2017&quot;百度之星&quot;程序设计大赛 - 复赛1005&amp;&amp;HDU 6148 Valley Numer【数位dp】

Valley Numer Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 311    Accepted Submission(s): 165 Problem Description 众所周知,度度熊非常喜欢数字. 它最近发明了一种新的数字:Valley Number,像山谷一样的数字. 当一个数字,从左到右依次看过去数字没有出现先递增接

2017&quot;百度之星&quot;程序设计大赛 - 复赛1003&amp;&amp;HDU 6146 Pok&#233;mon GO【数学,递推,dp】

Pokémon GO Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 171    Accepted Submission(s): 104 Problem Description 众所周知,度度熊最近沉迷于 Pokémon GO. 今天它决定要抓住所有的精灵球! 为了不让度度熊失望,精灵球已经被事先放置在一个2*N的格子上,每一个格子上都

2017&quot;百度之星&quot;程序设计大赛 - 复赛1001&amp;&amp;HDU 6144 Arithmetic of Bomb【java大模拟】

Arithmetic of Bomb Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 129    Accepted Submission(s): 94 Problem Description 众所周知,度度熊非常喜欢数字. 它最近在学习小学算术,第一次发现这个世界上居然存在两位数,三位数……甚至N位数! 但是这回的算术题可并不简单,由于

美团点评2017秋招笔试编程题

美团点评2017秋招笔试编程题 1, 大富翁游戏,玩家根据骰子的点数决定走的步数,即骰子点数为1时可以走一步,点数为2时可以走两步,点数为n时可以走n步.求玩家走到第n步(n<=骰子最大点数且是方法的唯一入参)时,总共有多少种投骰子的方法. 题解: 写出前面的几个, 1 -> 1;   2 -> 2 ;  3 -> 4;   4 -> 8; 5 -> 16; 6 -> 32; 可以得到是 二的 n-1 次幂. #include <cstdio> int

第六届华为创新杯编程大赛-进阶1第1轮

洞穴逃生 描述: 精灵王子爱好冒险,在一次探险历程中,他进入了一个神秘的山洞.在洞穴深处,精灵王子不小心触动了洞穴内暗藏的机关,整个洞穴将很快塌陷,精灵王子必须尽快逃离洞穴.精灵王子的跑步速度为17m/s,以这样的速度可能是无法逃出洞穴的.庆幸的是精灵王子拥有闪烁法术,可在1s内移动60m,不过每次使用闪烁法术都会消耗魔法值10点.精灵王子的魔法值恢复的速度为4点/s,只有处在原地休息状态时才能恢复. 现在已知精灵王子的魔法初值M,他所在洞穴中的位置与洞穴出口之间的距离S,距离洞穴塌陷的时间T.