题目以下。ios
规则
杰克船长此次运气不错,抢到了一大堆金币。但他立刻又开始发愁了, 由于如何给你们分金币,一直都是件不容易的事,每次杰克船长都要头疼好几天。算法
关于分金币,海盗的行规是这样的:函数
- 每次行动,船长会根据各个海盗的表现记功,过后论功行赏,给你们分金币。
- 分战利品的时候,海盗们会随意的站成一排,船长给每一个人发一袋金币。袋子里的金币数目有多有少,但船长保证每一个海盗至少会分到一枚金币。
- 拿到金币后,相邻的两个海盗会互相比较。若是其中一个功劳高些,那他的金币必须多一些,若是两我的分数同样,他们的金币必须同样。不然,海盗们就以为不公平,要闹事,甚至造反。
怎么样才能用最少的金币让你们都满意呢? 领导这帮海盗可不轻松。code
据说此次比赛中有一位未来要成为海贼王的男人,杰克船长相信他必定能解决这个麻烦。blog
输入说明
在程序当前目录下存在execute.stdin文件,程序从execute.stdin中取得输入数据。
execute.stdin中存放着N(N<100)个十进制正整数,数字之间用空格格开。
每一个数字都表明某个海盗的功劳,值范围为(1, 100)。ci
输出说明
输出一个正整数,表明让全部海盗都满意的最少的金币数。get
找出序列中全部的局部最小值,给对应位置的船员分配一枚金币,而后两侧的依次金币数加1。io
在两个局部最小值之间有一个局部最大值,例如一段序列... 11 12 13 14 12 11 ...
,若两侧的11是局部最小值,14是局部最大值,则从左往右,11到13的位置分别分配1 2 3枚金币;从右往左,11到12的位置分别分配1 2枚金币,14的位置若是分配3枚金币的话不能知足比13多的条件,因此14的位置分配4个金币。因此,从两侧的局部最小值依次递增到局部最大值位置的时候,局部最大值对应位置取较大的金币数。stream
对于序列的最左和最右位置,若是第一个数小于/大于第二个数,则其是局部最小/大值;若是最后一个数小于/大于倒数第二个数,则其是局部最小/大值;基础
#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; }