CodeVs 1098 均分纸牌

摘要:介绍关于纸牌均分题目算法第一种自己原创,另一种是网上普遍算法。

题目:

题目描述 Description

有 N 堆纸牌,编号分别为 1,2,…, N。每堆上有若干张,但纸牌总数必为 N 的倍数。可以在任一堆上取若于张纸牌,然后移动。
  移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 的堆上;在编号为 N 的堆上取的纸牌,只能移到编号为 N-1 的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。
  现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。

  例如 N=4,4 堆纸牌数分别为:
  ① 9 ② 8 ③ 17 ④ 6
  移动3次可达到目的:
  从③取 4 张牌放到④(9 8 13 10) -> 从③取 3 张牌放到②(9 11 10 10)-> 从②取 1 张牌放到①(10 10 10 10)。

输入描述 Input Description

第一行N(N 堆纸牌,1 <= N <= 100)
第二行A1 A2 … An (N 堆纸牌,每堆纸牌初始数,l<= Ai <=10000)

输出描述 Output Description

输出至屏幕。格式为:
所有堆均达到相等时的最少移动次数。‘

样例输入 Sample Input

4
9 8 17 6

解题思路:

移牌规则,决定了大于平均堆牌数的堆必须至少要进行一次分牌把其多余的牌数分出去,分法有三种:分给左边、分给右边、两边分。

第一种,可能出现右边少了,需要将左边的牌通过H分发的情况,此时多出两次,即多了3次分发操作。第二种类似第一种。

第三种,先计算出两边需要分发的需求,需要多少分发多少。

显然应采取第三种分发策略。

子问题解决方法得到:每次将一个最大的堆按两边需求,向两边分发。

解题步骤:

1.    
得最大堆的编号vector<int>::iterator iter

2.    计算左右需求divLeft、divRight,按需要分发。分发一次计数器++

3.    
goto第一步,如果最大编号的值为平均值,表示分发完成。

#include<iostream>

#include<vector>

#include<algorithm>

#include<numeric>

usingnamespace std;

int main(){

  /*测试数据*/

//int n
= 4;

//vector<int>
v{ 9, 8, 17, 6 };

  

  /*输入数据,保存入vector v中*/

int n = 6;

int m;

vector<int> v;

cin
>> n;

while (cin
>> m)

{

v.push_back(m);

}

/*解题*/

  int avg =
accumulate(v.begin(), v.end(), 0) / n;//average平均值

vector<int>::iterator iter =
max_element(v.begin(), v.end());//从第一个最大的数开始移动

int count =
0;//计数,每移动一次,++

while (*iter
>avg)//知道最大一个数位平均数为止,表示分堆完毕。否则进行分堆

{

int
numsLeft = iter - v.begin();

int
numsRight = v.end() - iter - 1;

int divLeft
= numsLeft*avg - accumulate(v.begin(), iter, 0);

int
divRight = numsRight*avg - accumulate(iter + 1, v.end(), 0);

if
(divRight > 0){//左边需要移动

*(iter
+ 1) += divRight;

*iter
-= divRight;

count++;

}

if
(divLeft > 0){//右边需要移动

*(iter
- 1) += divLeft;

*iter
-= divLeft;

count++;

}

iter
= max_element(v.begin(), v.end());//获取下一个最大的数

}

   /*输出结果*/

cout
<< count;

return 0;

}

其他方法(即网上普遍方法):

思路:

从第一堆到最后一堆,通过其右邻的堆(i+1),依此将当前堆i设为均堆,如果当前堆已经为均堆,堆编号++

主要步骤:

1. 计算右邻堆需要牌数      div
= a[i] - average;

2. 右邻堆根据div正负,减牌或者加牌。a[i+1] += div;

主要代码:

if (v[i]
!= avg)//是否为均堆

{

div
= v[i] - avg;//计算右邻堆需要牌数,为正表示分给右邻堆,为负表示从右邻堆得到。

v[i]
= avg;

v[i
+ 1] += div;

step++;

}

/*problem:纸牌均分http://codevs.cn/problem/1098/

**author:shaoning.ding

**time:2015.5.1

*/

#include<iostream>

#include  <vector>

#include<numeric>

usingnamespace std;

int main()

{

/*测试数据*/

int n = 4;

vector<int> v{
9, 8, 17, 6 };

/*input数据,保存vector v中*/

//int
n,int m;

//vector<int>
v;

//cin
>> n;

//while
(cin >> m)

//{

//  v.push_back(m);

//}

/*解题*/

int avg =
accumulate(v.begin(), v.end(), 0) / n;//avg平均值

int step =
0;

for (int i = 0;
i<n; i++)

{

int div =
0;

  if (v[i]
!= avg)//是否为均堆

{

div
= v[i] - avg;//计算右邻堆需要牌数,为正表示分给右邻堆,为负表示从右邻堆得到。

v[i]
= avg;

v[i
+ 1] += div;

step++;

}

}

/*输出结果*/

cout
<< step;

}

时间: 2024-11-07 20:51:33

CodeVs 1098 均分纸牌的相关文章

1098 均分纸牌

1098 均分纸牌 2002年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 有 N 堆纸牌,编号分别为 1,2,…, N.每堆上有若干张,但纸牌总数必为 N 的倍数.可以在任一堆上取若于张纸牌,然后移动. 移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 的堆上:在编号为 N 的堆上取的纸牌,只能移到编号为 N-1 的堆上:其他堆上取的纸牌,可以移到相邻左边或右边的堆上. 现在要求找出一种移动

code vs 1098 均分纸牌(贪心)

1098 均分纸牌 2002年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description 有 N 堆纸牌,编号分别为 1,2,…, N.每堆上有若干张,但纸牌总数必为 N 的倍数.可以在任一堆上取若于张纸牌,然后移动. 移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 的堆上:在编号为 N 的堆上取的纸牌,只能移到编号为 N-1 的堆上:其他堆上取的纸牌,可以移到相邻左边或右边的堆上. 现在要求找出一

wikioi 1098 均分纸牌

题目描述 Description 有 N 堆纸牌,编号分别为 1,2,…, N.每堆上有若干张,但纸牌总数必为 N 的倍数.可以在任一堆上取若于张纸牌,然后移动. 移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 的堆上:在编号为 N 的堆上取的纸牌,只能移到编号为 N-1 的堆上:其他堆上取的纸牌,可以移到相邻左边或右边的堆上. 现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多. 例如 N=4,4 堆纸牌数分别为: ① 9 ② 8 ③ 17 ④ 6 移动3次可达到目的

【贪心】【codevs】1098 均分纸牌

http://codevs.cn/problem/1098/ Q:N摞纸牌,每摞纸牌张数随机,每摞纸牌只能移动到相邻的纸牌摞上去,求最小的移动次数,使得每摞纸牌的张数一致. A:从头到尾扫一遍,只要当前这摞纸牌的张数不是每摞牌最终应该达到的平均值,就将其多的或少的纸牌移动或取自下一摞纸牌,同时将移动次数加1 #include<bits/stdc++.h> using namespace std; int p[105]; int n; int sum, avg; int ans; int mai

1098 均分纸牌 ——http://codevs.cn/problem/1098/

第一部分:题目 题目描述 Description 有 N 堆纸牌,编号分别为 1,2,…, N.每堆上有若干张,但纸牌总数必为 N 的倍数.可以在任一堆上取若于张纸牌,然后移动. 移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 的堆上:在编号为 N 的堆上取的纸牌,只能移到编号为 N-1 的堆上:其他堆上取的纸牌,可以移到相邻左边或右边的堆上. 现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多. 例如 N=4,4 堆纸牌数分别为: ① 9 ② 8 ③ 17 ④ 6 移

【codevs】【贪心】1098均分纸牌

有 N 堆纸牌,编号分别为 1,2,…, N.每堆上有若干张,但纸牌总数必为 N 的倍数.可以在任一堆上取若于张纸牌,然后移动. 移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 的堆上:在编号为 N 的堆上取的纸牌,只能移到编号为 N-1 的堆上:其他堆上取的纸牌,可以移到相邻左边或右边的堆上. 现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多. 例如 N=4,4 堆纸牌数分别为: ① 9 ② 8 ③ 17 ④ 6 移动3次可达到目的: 从 ③ 取 4 张牌放到 ④

CODE[VS] 1098 均分纸牌 ( 2002年NOIP全国联赛提高组)

arr[i] :表示每个牌堆的纸牌的数目 平均值 :当纸牌数都一样多时,纸牌的数目 从左向右考虑,每堆纸牌有三种状态: 1) arr[i] == 平均值,考虑arr[i+1] 2) arr[i] < 平均值,此时由arr[i+1]移给arr[i]纸牌. => 移动纸牌数:(平均值 - arr[i])张    注:   考虑此时,arr[i]缺牌,那么i右边的牌堆必然多牌,无论哪堆多牌,必然有由arr[i+1]将牌移给arr[i]的过程. 3) arr[i] > 平均值,此时由arr[i]

CODEVS 2485 七夕祭 - 贪心+中位数【环形均分纸牌问题】

CODEVS 2485 七夕祭 Sol: 当行的平均值不为整数时,不能均分,列同理. 对行和列分别做一次环形均分纸牌问题. AC CODE: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 100000 + 100; int read(){ int x=0,f=1;char ch=' '; while(ch>'9'||ch<'0

洛谷 P1031 均分纸牌

P1031 均分纸牌 题目描述 有 N 堆纸牌,编号分别为 1,2,…, N.每堆上有若干张,但纸牌总数必为 N 的倍数.可以在任一堆上取若于张纸牌,然后移动. 移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 的堆上:在编号为 N 的堆上取的纸牌,只能移到编号为 N-1 的堆上:其他堆上取的纸牌,可以移到相邻左边或右边的堆上. 现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多. 例如 N=4,4 堆纸牌数分别为: ①9②8③17④6 移动3次可达到目的: 从 ③ 取