题目链接:https://vjudge.net/problem/UVALive-6442
题意:给出一个有n个点并且每个点等距的圆环,有m个硬币放在圆环的随机位置上(多个硬币可以放在同一个位置),要你求使得每个硬币和相邻硬币距离相等时花费的最小值。(保证m是n的因数)
花费的定义:所有硬币中移动步数的最大值。
思路:对于这m个硬币,我们可以先随便找一个他们要等距后要放的位置,然后我们把硬币的初始位置排下序,然后依次计算这些硬币要放到相应位置要走的最小步数(正负代表方向,正代表向后,负代表往前),找出最大值和最小值(不是绝对值的最大值和最小值),对于我们找到的最大值,没有一个要往后移动的硬币要移动的步数的绝对值大于它,对于我们找到的最小值,没有一个要往前移动的硬币要移动的步数的绝对值大于它,因为我们要求最小的最大步数,所有我们可以通过使得把要放的位置同时向前或者向后移动 x 个位置,使得这个“最大值”和“ 最小值”的绝对值接近,从而使得要么要求的最大步数最小(因为他们分别是往后移和往前移的硬币中要移动的最大距离,我们可以通过移动初始位置来使他们其中绝对值最大的那个的步数减少,从而使总花费最小)。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int s[20050]; int main(){ int t; int n,m; int mx,mn,sum,nb; nb=0; scanf("%d",&t); int i,j,k; while(t--){ nb++; scanf("%d%d",&n,&m); for(i=0;i<m;i++){ scanf("%d",&s[i]); } sort(s,s+m); k=n/m; mn=1e7; mx=-1e7; sum=0; for(i=0;i<m;i++){ if(s[i]-sum>mx){//找出向后走最大的步数 mx=s[i]-sum; } if(s[i]-sum<mn){//找出向前走最大的步数 mn=s[i]-sum; } sum+=k; } printf("Case #%d: ",nb); printf("%d ",(mx-mn+1)/2);/*通过把初始要放的位置往前或往后移使得他们的绝对值接近,此时当 他们绝对值相等或者差为1时,我们就不能同个往前或往后移来使得最大步数减小(因为当这个时候不管 你往前还是往后移时都只会使当前最小值的绝对值变成最大移动步数或者是最大值的绝对值变成最小步数) 例:当最大值为7,最小值为-2时,我们通过把要放的位置往前移2步,现在最大值为5,最小值为-4,无论你 怎么移都不能使得他们绝对值中最大的那个减低,经过简单的推理就得最出答案是(mx-mn+1)/2 */ } return 0; }