zoukankan      html  css  js  c++  java
  • 1038 Recover the Smallest Number (30 分)

    这个题给(30)分也太拉了。

    题意

    给出若干可能有前导零的数字串,将它们按某个顺序拼接,使生成的数最小。

    思路

    很多读者看了样例,会觉得只要把这些数字串按字典序从小到大排序,然后按顺序输出就可以了。这种想法方向似乎是对的。但是来看样例中的例子: {“32”,“321”},排序结果是{“32”,“321”},那么获得的答案就是32321,但是实际上有更小的答案32132。所以这种贪心是错误的。

    那么,如何获得正确的答案呢?其实上面的做法已经很接近最小数字了,只是局部上有一些问题。根据上面的反例,可以想到这样的贪心策略:对数字串(S_1)(S_2),如果(S_1+S_2<S_2+S_1)(加号表示拼接),那么把(S_1)放在(S_2)的前面;否则,把(S_2)放在(S_1)的前面。但是这样的策略能否保证结果的正确性呢?

    下面尝试进行如下证明:
    证明:假设有数字串(S_1+S_2+ cdots +S_{k-1}+S_k+ cdots +S_n),且对任意(i∈[1,n]),有(S_k+S_1<S_1+S_k)成立(也即是说,(S_k)与其他数字串拼接时,(S_k)总是排在前面更优)。那么考虑(S_{k-1}+S_k)部分,显然有(S_k+S_{k-1}<S_{k-1}+S_k)成立,因此(S_1+S_2+ cdots +S_k+S_{k-1}+ cdots +S_n<S_1+S_2+ cdots +S_{k-1}+S_k+ cdots +S_n)成立,这样(S_k)就提前了一个位置。接下来考虑(S_{k-2}+S_k)部分,同理可以得到(S_1+S_2+ cdots +S_k+S_{k-2}+ cdots + S_n<S_1+S_2 + cdots +S_{k-2}+S_k+ cdots +S_n),因此(S_k)又提前了一个位置。
    依此类推,最终(S_k)将提前到第一个位置,得到(S_k+S_1+S_2 + cdots +S_{k-1}+S_{k+1}+ cdots +S_n)。同理,对(S_k)之后的部分也可以使用同样的思路将某个数字串提前到(S_k)的后面,使得结果串更小。这样的操作直到所有数字串都处理完毕,就得到了所求的最小数。证毕。

    具体实现时,可以将上面的思路写在cmp函数中,然后直接使用sort函数实现。注意:排序后需要去掉整个序列的前导零。

    const int N=1e4+10;
    string s[N];
    int n;
    
    bool cmp(string a,string b)
    {
        return a+b < b+a;
    }
    
    int main()
    {
        cin>>n;
    
        for(int i=0;i<n;i++) cin>>s[i];
    
        sort(s,s+n,cmp);
    
        string res;
        for(int i=0;i<n;i++) res+=s[i];
    
        int k=0;
        while(res[k] == '0' && k+1 < res.size()) 
            k++;
        cout<<res.substr(k)<<endl;
        //system("pause");
        return 0;
    }
    
  • 相关阅读:
    机器学习--强化学习
    机器学习--深度学习
    机器学习--维度灾难
    机器学习--最优化
    机器学习--降维
    机器学习--聚类
    机器学习--模型提升
    Git和gitHub用户名 邮箱
    Git线上操作
    版本控制器:Git
  • 原文地址:https://www.cnblogs.com/fxh0707/p/14415071.html
Copyright © 2011-2022 走看看