一、题目信息
1、题目链接:[NOIP2002 提高组] 均分纸牌 - 洛谷
二、分析
1、题意:想象自己是一维纸牌堆上的纸牌搬运工,我们需要将纸牌从有剩余(大于平均值)的堆移动到有欠缺(小于平均值)的堆
2、条件:
- 所有纸牌可以被平均n分,无需考虑最终纸牌不够或者有剩余
- 我们无需考虑移动的纸牌的数量,即假定每次我们移动的纸牌的数量不多不少刚刚好
3、最少移动次数:
- 向有欠缺的纸牌堆补充纸牌时尽可能地补充使得纸牌堆的纸牌欠缺数量尽可能减少,如当前纸牌堆欠缺5张纸牌而自己手上有5张纸牌时应向纸牌堆补充5张纸牌,而非想着说后面可能还有纸牌堆有欠缺而保留几张纸牌,这样徒增移动次数
- 欠缺纸牌堆的纸牌补充来源应是最近的有剩余纸牌堆,多个欠缺纸牌堆有共同的最近剩余纸牌堆时,距离公共最近剩余纸牌堆更远的欠缺纸牌堆纸牌补充优先级更高。从而在纸牌补充过程中,欠缺纸牌堆的最近有剩余纸牌堆可能会发生变化
- 纸牌移动的路径如果有重叠的可以合并
- 可以看出我们只需考虑最边界的欠缺纸牌堆和有剩余纸牌堆的相对距离,而中间的纸牌堆无论是欠缺还是剩余还是恰为平均数都只是纸牌移动的踏板
三、代码
#include<iostream>
#include<vector>
using namespace std;
int main(){
int n,total=0;
cin>>n;
vector<int> arr(n);
for(int i=0;i<n;i++){
cin>>arr[i];
total+=arr[i];
}
int aver=total/n;
//remain表示遍历到当前纸牌堆纸牌剩余多少或欠多少,result为最少移动次数
int remain=0,result=0;
//从左到右遍历纸牌堆
for(int i=0;i<n;i++){
remain+=(arr[i]-aver);
//若当前纸牌有剩余,意味着右侧有纸牌堆的纸牌数量有欠缺,需要向右移动纸牌到该纸牌堆补充并且经过当前位置i,因此移动次数+1
//若当前纸牌欠缺,意味着左侧有纸牌堆的纸牌数量有欠缺,需要向左移动纸牌补充并且经过当前位置i,因此移动次数+1
if(remain!=0) result++;
}
cout<<result;
return 0;
}