均分纸牌(Noip2002)
1320:【例6.2】均分纸牌(Noip2002)
时间限制: 1000 ms 内存限制: 65536 KB
提交数: 3537 通过数: 1839
【题目描述】
有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)。
【输入】
n(n 堆纸牌,1 ≤ n ≤ 100)
a1 a2 … an (n 堆纸牌,每堆纸牌初始数,l≤ ai ≤10000)。
【输出】
所有堆均达到相等时的最少移动次数。
【输入样例】
- 4
- 9 8 17 6
【输出样例】
- 3
- 例题不怎么详的解:
前辈们告诉我们,OI的很多题目想要解出来是需要很多奇巧淫技的,多积累点奇怪的思路和技巧,不仅对提升成绩有帮助,还对自己大脑开发有好处(一本正经)。- 实际上很多OI题都要靠奇葩的技巧,就像其他学科竞赛那样。。。
- 这一题也是如此。
很多人一上来看到这题目就直接懵逼了,没有头绪,难不成让我用搜索做?
于是乎玄乎的来了,我们代入一点逆向的思想,分析输入数据和输出数据的关系,震惊地发现原来所有牌堆中牌的总数平分到每一个堆中(即平均值)就是最后均分的结果,也照应了题目。
好吧我承认这很容易想出来,因为题目给出的暗示很明显:
现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。- 好的,我实力眼瞎没看到,刚看到这道题我差点就去搜索了。。。所以说啊,认真看题无论在哪里都是第一要素!!!
- 算法分析:
回到正题,给出的n堆纸牌中,由于分配不均,肯定存在牌数最多的一堆,我们就从这里开始。经过简单分析,因为题目只允许将中间牌堆上的牌放到左右两边,得出以下参考思路:- 我们将所有牌的数量除以总堆数的结果称为平均值;
我们将某一堆上牌的总数与平均值之差称为需求值;- 找到牌数最多的牌堆,将牌分成两部分,一部分的数量是该堆左边每堆牌需求值总和,另一部分的数量是右边每堆牌需求值总和,然后分别放置到左右两边。
向左右两边继续执行这样的操作,由于已经执行过的部分已经达到平均值,无需改变,所以这种算法具有无后效性,只需将最中间的牌向两边摊开就行。- 这时我突然意识到一个问题,如果用这种思路设计算法,那么代码设计会相对繁琐,因为要实现规划左右两段的功能,于是竞赛书上的写法使我虎躯一震,真的没想到还有这种操作,果然竞赛靠的还是一个巧。
那就是:- 假设一组牌堆,3 7 17 13,写成需求值的形式是-7 -3 7 3,我们把 -7 移到 -3 里去,把 -7 变成 0,-3 变成 -10(相当于-3那一堆挪7张牌到-7那一堆,但是可以在算法中写成此种形式),
-10 再移到 7 里去,7 变成 -3,最后把 -3 移到 3 里去,大功告成。- 很明显这种思路比我的思路要来的简单一些,代码量更少,那么我就只分析这种算法(其实是我懒)。
- 设置一个关键数组a,储存所有牌堆的牌数。
设置一个变量avg,储存均值。
设置一个变量tot,储存移动总步骤。
- 我们首先要将需求值计算出来放进一个数组,我嫌麻烦,所以将数组a再次利用了一次,将需求值覆盖原数组。
接下来就是算法核心部分的编写,我们需要遍历一遍数组,执行上面那个思路:
- for(int t=i;t<j;t++)
- {
- a[t+1]+=a[t];
- a[t]=0;
- tot++;
- }
这就是核心代码,很简单,不过有些细节还要处理。
- 注意:要 素 察 觉,如果开头和结尾的牌堆的需求值为0,那么此牌堆无需移动。正确姿势应该是从第一个需求值不为0的牌堆移动到最后一个需求值不为0的牌堆。
而且,在移动过程中如果出现恰好前后两牌堆需求值合并得到的值为0的情况,可以跳过一步,相当于遍历到此牌堆时,前面的需求值恰好抵消,等同于已经完成了一轮均分。
因此,现在需求值为0的那个牌堆不需要再移动。
得到如下代码:
- i=0;j=n-1;
- while(a[i]==0&&i<n) i++;
- while(a[j]==0&&j>1) j--;
- for(int t=i;t<j;t++)
- {
- if(a[t]==0) continue;
- a[t+1]+=a[t];
- a[t]=0;
- tot++;
- }
- 样例代码:
- #include<iostream>
- #include<cstdio>
- #include<cstdlib>
- #include<cstring>
- using namespace std;
- int main()
- {
- int avg=0,n,a[101],i,tot=0,j;
- scanf("%d",&n);
- for(i=0;i<n;i++)
- {
- scanf("%d",&a[i]);
- avg+=a[i];
- }
- avg/=i;
- for(j=0;j<n;j++) a[j]-=avg;
- i=0;j=n-1;
- while(a[i]==0&&i<n) i++;
- while(a[j]==0&&j>1) j--;
- for(int t=i;t<j;t++)
- {
- if(a[t]==0) continue;
- a[t+1]+=a[t];
- a[t]=0;
- tot++;
- }
- printf("%d",tot);
- return 0;
- }
2019-02-08 19:36:03
均分纸牌(Noip2002)的更多相关文章
- 洛谷-均分纸牌-NOIP2002提高组复赛
题目描述 Description 有 N 堆纸牌,编号分别为 1,2,…, N.每堆上有若干张,但纸牌总数必为 N 的倍数.可以在任一堆上取若于张纸牌,然后移动. 移牌规则为:在编号为 1 堆上取的纸 ...
- 贪心训练均分纸牌Noip2002
题目链接:https://www.luogu.com.cn/problem/P1031 题目描述 有N堆纸牌,编号分别为 1,2,…,N.每堆上有若干张,但纸牌总数必为N的倍数.可以在任一堆上取若干张 ...
- NOIP2002 均分纸牌
题一 均分纸牌 (存盘名: NOIPG1) [问题描述] 有 N 堆纸牌,编号分别为 1,2,…, N.每堆上有若干张,但纸牌总数必为 N 的倍数.可以在任一堆上取若于张纸牌,然后移动. 移牌规则为: ...
- code vs 1098 均分纸牌(贪心)
1098 均分纸牌 2002年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description 有 N 堆纸牌 ...
- NOIP200205均分纸牌
均分纸牌 描述 有 N 堆纸牌,编号分别为 1,2,…, N.每堆上有若干张 ...
- wikioi 1098 均分纸牌
题目描述 Description 有 N 堆纸牌,编号分别为 1,2,-, N.每堆上有若干张,但纸牌总数必为 N 的倍数.可以在任一堆上取若于张纸牌,然后移动. 移牌规则为:在编号为 1 堆上取的纸 ...
- 【洛谷p1031】均分纸牌
[博客园的第一条随笔,值得纪念一下] 均分纸牌[传送门] 洛谷上的算法标签是 这道题是一道贪心题,过了四遍才过(蒟蒻有点废) 第一遍的时候考虑的非常少,只想到了求出平均数→求差值→从左往右加差值: 这 ...
- 洛谷P1368 均分纸牌(加强版)
P1368 均分纸牌(加强版) 题目描述 有 N 堆纸牌,编号分别为 1,2,…, N.每堆上有若干张,纸牌总数必为 N 的倍数.可以在任一堆上取1张纸牌,然后移动. 移牌规则为:在编号为 1 堆上取 ...
- 洛谷P1031 均分纸牌
P1031 均分纸牌 题目描述 有 N 堆纸牌,编号分别为 1,2,…, N.每堆上有若干张,但纸牌总数必为 N 的倍数.可以在任一堆上取若干张纸牌,然后移动. 移牌规则为:在编号为 1 堆上取的纸牌 ...
随机推荐
- SpringBoot + Mybaties的逆向工程有数据库生成domain的过程
环境: jdk1.8 (适合springboot2.X以上版本) Maven(3.3.X以上) spring boot 2.1.6 Idea 2019.1\ 这里随便填 选择相应的Jar,如以下的勾 ...
- Apache Kafka工作流程| Kafka Pub-Sub Messaging
1.目标 在我们上一篇Kafka教程中,我们讨论了Kafka Docker.今天,我们将讨论Kafka Workflow.此外,我们将详细介绍Pub-Sub Messaging的工作流程以及Queue ...
- 自定义 Word 默认的 Normal.dotm 模板、更改 Word 默认字体、更改 Word 默认样式(16)
1. 引言 以Office 2016为例. 有没有遇见这样的问题: 每次新建一个 Word 空白文档打开后字体默认是等线,段落默认是单倍行距,默认标题也不是自己想要的样式,等一系列问题.每次打开都要调 ...
- python基础 — 致初学者的天梯
Python简介 Python是一种计算机程序设计语言.是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新 功能的添加,越来越多被用于独立的.大型项目 ...
- 20191210-RobotFramework常见问题解决
附加-问题解决 1. 执行robot用例的时候提示WebDriverException: Message: invalid argument: can't kill an exited proce ...
- PAT(B) 1055 集体照(Java)
题目链接:1055 集体照 (25 point(s)) 题目描述 拍集体照时队形很重要,这里对给定的 N 个人 K 排的队形设计排队规则如下: 每排人数为 N/K(向下取整),多出来的人全部站在最后一 ...
- redis网文
1.为什么说Redis是单线程的以及Redis为什么这么快!https://blog.csdn.net/chenyao1994/article/details/794913372.Redis上踩过的一 ...
- Restful与Spring MVC
Spring工作流程: 文件上传的处理: 解析参数的过滤器: <filter> <filter-name>MultipartFilter</filter-name> ...
- lucene中Field简析
http://blog.csdn.net/zhaoxiao2008/article/details/14180019 先看一段lucene3代码 Document doc = new Document ...
- asp.net core EF code first
以连接mysql数据库为例 一 安装组件 Microsoft.EntityFrameworkCore Microsoft.EntityFrameworkCore.Relational Microsof ...