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;
    }
    
  • 相关阅读:
    51nod 1087 1 10 100 1000(找规律+递推+stl)
    51nod 1082 与7无关的数 (打表预处理)
    51 nod 1080 两个数的平方和
    1015 水仙花数(水题)
    51 nod 1003 阶乘后面0的数量
    51nod 1002 数塔取数问题
    51 nod 1001 数组中和等于K的数对
    51 nod 1081 子段求和
    51nod 1134 最长递增子序列 (O(nlogn)算法)
    51nod 1174 区间中最大的数(RMQ)
  • 原文地址:https://www.cnblogs.com/fxh0707/p/14415071.html
Copyright © 2011-2022 走看看