使数字列表相等的最小移动次数

Minimum number of moves to equalize list of numbers

我们有一个包含 n 个正整数的数组。一个可接受的举措是将所有元素增加 1 或 2 或 5,除了一个元素。我们需要找出使所有数组元素都相等的最少操作次数。

经过搜索我发现了一种方法:

  1. 找出非最小元素与最小元素之间的所有差异。
  2. 通过使用找零硬币的方法,找到找零所需的最少硬币数量。
  3. Return所有这些最小硬币数的总和。

但是对于这个测试用例,这种方法失败了:

数组:1,5,5

最小操作数:3 (1,5,5 -> 1,6,6 -> 6,6,11 -> 11,11,11).

按照上述方法,我得到了 4。

任何人都可以建议正确的方法吗?

这是我的源代码:

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <climits>
using namespace std;

int input[10000];
int input1[10000];
int dp[4][1001];
int parent[4][1001];
int coins[4]={0,1,2,5};
int operation=0;
int main() {
    int t,n,i,j,count,sum,diff,prevdiff,min;
    for(i=1;i<1001;i++)
    {
        dp[0][i]=INT_MAX;
        parent[0][i]=INT_MAX;
    }
    for(i=0;i<4;i++)
    {
        dp[i][0]=0;
        parent[i][0]=-1;
    }
    for(i=1;i<1001;i++){
        for(j=1;j<4;j++){
            dp[j][i]=dp[j-1][i];
            parent[j][i]=parent[j-1][i];
            if(i>=coins[j]&&dp[3][i-coins[j]]<INT_MAX){

                if(dp[3][i-coins[j]]+1<dp[j][i]){
                    dp[j][i]=dp[3][i-coins[j]]+1;
                    parent[j][i]=j;
                }
            }
        }
    }
    cin>>t;
    while(t>0){
        cin>>n;
        min=INT_MAX;
        for(i=0;i<n;i++)
        {
            cin>>input[i];
            if(input[i]<min){
                min=input[i];
            }
            //input1[i]=input[i];
        }

        //sort(input,input+n);

        count=0;
        sum=0;

        for(i=0;i<n;i++){
            count=count+dp[3][input[i]-min];
        }

        cout<<count<<endl;
        t--;
    }
    /*
    for(i=1;i<1001;i++){
        if(dp[3][i]!=minCoins(i))
            cout<<dp[3][i]<<" "<<minCoins(i)<<endl;
    }
    */
    return 0;
}

您发现的方法不适用于由 1、2 和 5 组成的元素集。如您所说,对于 1, 5, 5,该方法导致 4 次操作(对于 "coin change"),例如:

1, 5, 5 -> 1, 3, 5 -> 1, 1, 5 -> 1, 1, 3 -> 1, 1, 1

为了均衡所有元素,将除一个元素以外的所有元素增加 1、2 或 5,本质上与将一个元素减少相应的值相同(参见 this answer). If you view your problem this way, then it is equal to this 问题。

后一个问题的answer说明仅考虑最小元素和非最小元素的区别是不够的。您还必须考虑所有元素与最小元素 - 1 和最小元素 - 2 的差异。例如,对于 1, 5, 5,这会导致以下操作:

1, 5, 5 -> 0, 5, 5 -> 0, 0, 5 -> 0, 0, 0

1, 5, 5 -> -1, 5, 5 -> -1, 0, 5 -> -1, -1, 5 -> -1, -1, 0 -> -1, -1, -1

如您所见,对于您的示例,考虑所有元素与最小元素之间的差异 - 1 给出了使所有元素相等所需的最少操作数,即 3。

您应该调整您的代码以反映这种方法。

将除1以外的所有数字增加1,2或5等同于将该数字减少1,2或5。因此,这道题可以转换为另一道题-

我们希望通过仅使用 1 个操作使所有数字相等,即将特定数字减少 1,2 或 5。

为了解决这个问题,我们可以找到数组中的最小数字。所有数字的最终值将是 [min(Array)-4, min(Array)] 我们可以迭代所有 5 个值,并且对于每个值,我们可以找到使所有元素成为所选值的最小移动次数。最后取我们在每个测试用例中得到的所有 5 个答案中的最小值。那将是结果。这是我的 C++ 代码 -

#include<bits/stdc++.h>
using namespace std;

#define int long long int

signed main(){
    int t;
    cin>>t;
    while(t--){
        int n, res = INT_MAX, mini = INT_MAX, ans, temp;
        cin>>n;
        int A[n];
        for(int i=0;i<n;i++){
            cin>>A[i];
            mini = min(mini, A[i]);
        }
        for(int i=mini-4;i<=mini;i++){
            ans = 0;
            for(int j=0;j<n;j++){
                temp = A[j]-i;
                temp = temp/5+(temp%5)/2+(temp%5)%2;
                ans += temp;
            }
            res = min(ans, res);
        }
        cout<<res<<"\n";
    }

    return 0;
}