【问题标题】:Minimum number of moves to equalize list of numbers使数字列表相等的最小移动次数
【发布时间】:2015-02-27 23:13:39
【问题描述】:

我们有一个由 n 个正整数组成的数组。一个可接受的举措是将所有元素增加 1 或 2 或 5,但一个元素除外。我们需要找出使所有数组元素相等的最小操作数。

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

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

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

数组: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,该方法有效,但如果您有元素 1、2 和 5,则该方法无效。

标签: c++ algorithm dynamic-programming


【解决方案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;
}

【讨论】:

    【解决方案2】:

    您发现的方法不适用于由 1、2 和 5 组成的元素集。正如您所说,对于 1, 5, 5,该方法导致 4 次操作(对于“硬币变化”),对于示例:

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

    为了均衡所有元素,将除一个元素之外的所有元素增加 1、2 或 5,本质上与将一个元素减少相应值相同(请参阅this 答案)。如果你这样看你的问题,那么它等于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。

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

    【讨论】:

    • 感谢您解释这种方法。我以前读过这种方法但我不明白。现在清楚了。
    • 不客气!很高兴我的回答对您有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    • 2022-08-24
    • 1970-01-01
    • 2019-02-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多