zoukankan      html  css  js  c++  java
  • [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;
    }
    
    

    运行结果

  • 相关阅读:
    HTML5 Shiv – 让该死的IE系列支持HTML5吧(转)
    sql之left join、right join、inner join的区别
    一道JS的简单算法题
    逆波兰式计算字符串公式
    前端编程,语义化
    罗列各种排序Mark
    关于JS动画和CSS3动画的性能差异
    各种算法题MARK
    Html笔记【不定时更新】
    CSS3笔记【不定时更新】
  • 原文地址:https://www.cnblogs.com/Ran-Chen/p/9390040.html
Copyright © 2011-2022 走看看