本文主要是介绍2018 CodeM初赛A轮 下棋答案(B题) (第二道题),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
题目:
有一个1*n的棋盘, 上面有若干个棋子,一个格子上可能有多个棋子,
你每次操作是先选择一个棋子,然后选择一下两个操作中的一个:
(1)若该棋子不在(1,1),让这个棋子往左走一格,即从(1,x)走到(1,x - 1);
(2)若该棋子不在(1,n),且这个棋子曾静到达过(1,1),让这个格子往右走一格,即从(1,x)走到(1,x+1)。
给定一开始每个各自上有几个棋子,再给定目标每个格子上上需要几个棋子,求最少需要多少次操作。
输入:
第一行一个正整数n表示棋盘大小。
第二行n个非负整数a_1,a_2,。。。,a_n 表示一开始(1,i)上有几个棋子。
第三行n个非负整数b_1,b_2,。。。,b_n 表示目标局面里的(1,i)上有几个棋子。
输出:
输出一个非负整数,表示最少需要几次操作。
例子:
输入:
5
0 0 1 1 0
1 0 0 0 1
输出:
9
题目分析:
典型的贪心法问题,目标数组减去起始数组,得到的向量中,如果元素为负,表示拥有多余的棋子;如果元素为正,表示,需要额外棋子,根据操作的定义,我们可以想到最有的策略是:棋盘中最右边的多余的棋子,给最左边需要的额外的棋子,坐标的相减即为所需的操作次数,而遇到在多余棋子坐标右边的需要的棋子,就需要向左移到头,再向右移,所需的操作为两个点的坐标相加。
贪心总结三点:
1、相差为0的元素,代表不移动
2、目标需要棋子的坐标如果在含有棋子的坐标的右边,则需要移动到最左边,然后再向右移动
3、目标需要棋子的坐标如果在含有棋子的坐标的左边,则只需要向左移动相应格子即可
而我们的贪心算法要尽可能是第三点的操作最多,则可满足题意。
代码
代码核心:定义两个队列,一个队列是拥有多余棋子的队列(这个队列是从右向左入队),另一个是需要棋子的队列(这个队列是从左向右入队),根据最有策略,列队入队的方向有所不同,注意队列还要保存坐标信息,当队首的棋子数为零则出队(这里的棋子数包括所需的棋子数或是多余的棋子数)。第二步就需要判断位置信息,利用位置来确定操作次数。代码如下:
//
// main.cpp
// codeM初赛2
//
// Created by Mr Gao on 2018/6/9.
// Copyright © 2018年 Mr Gao. All rights reserved.
//
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int main(int argc, const char * argv[]) {
// insert code here...
int n;
cin>>n;
if(n == 0)
cout<<0<<endl;
vector<long long> start(n);
vector<long long> end(n);
for(int i = 0; i < n; i++)
cin>>start[i];
for(int i = 0; i < n; i++)
cin>>end[i];
queue<pair<long long,int>> hasPiece;
queue<pair<long long,int>> needPiece;
for(int i = 0; i < n; i++){
long long diff = end[i] - start[i];
if(diff > 0)
needPiece.push(pair<long long,int>(diff, i));
}
for(int i = n - 1; i >= 0; i--){
long long diff = end[i] - start[i];
if(diff < 0)
hasPiece.push(pair<long long,int>(-diff, i));
}
long long ret = 0;
while(!hasPiece.empty()){
if(hasPiece.front().first >= needPiece.front().first && hasPiece.front().second > needPiece.front().second){
ret += needPiece.front().first * (hasPiece.front().second - needPiece.front().second);
hasPiece.front().first -= needPiece.front().first;
needPiece.front().first = 0LL;
}
else if(hasPiece.front().first < needPiece.front().first && hasPiece.front().second > needPiece.front().second){
ret += hasPiece.front().first * (hasPiece.front().second - needPiece.front().second);
needPiece.front().first -= hasPiece.front().first;
hasPiece.front().first = 0LL;
}
else if(hasPiece.front().first >= needPiece.front().first && hasPiece.front().second < needPiece.front().second){
ret += needPiece.front().first * (needPiece.front().second + hasPiece.front().second);
hasPiece.front().first -= needPiece.front().first;
needPiece.front().first = 0LL;
}
else if(hasPiece.front().first < needPiece.front().first && hasPiece.front().second < needPiece.front().second){
ret += hasPiece.front().first * (needPiece.front().second + hasPiece.front().second);
needPiece.front().first -= hasPiece.front().first;
hasPiece.front().first = 0LL;
}
if(hasPiece.front().first == 0LL)
hasPiece.pop();
if(needPiece.front().first == 0LL)
needPiece.pop();
}
cout<<ret<<endl;
return 0;
}
这篇关于2018 CodeM初赛A轮 下棋答案(B题) (第二道题)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!