FZU 2111 Min Number

暴力

训练的题目,给出一个数字(最长1000位即10^1000),给出m表示交换次数(每次可以交换任意两位的数字),问交换后得到的最小数字。注意,数字不能有前导0,另外有m次交换机会,但不必全部用完,只要交换到最小数字了就可以退出

为了得到最小数字,就是从高位开始,不断找最小的数字放到高位(但第一位要特殊处理不能为0)。如果现在使第i位最小,从第i到最后一位扫描找到最小值然后交换然后交换次数减1,如果刚好第i位就是最小值,则不交换,直接跳过,所以交换次数不能减1。如果m>len,即大于数字的位数,那么显然后面的交换机会都是多余的,最多交换len次就可以退出了

所以结束枚举的条件是,以为枚举了全部len位或者交换机会用完了

一开始算出时间复杂度以为暴力超时,其实没有,1000*100*100=10^7,刚好没超

不够程序跑出了0ms也真的是……

#include <cstdio>
#include <cstring>
#define N 1010
#define INF 0x3f3f3f3f

int a[N];
char str[N];
int m,n;

void solve(int m)
{
    int p=2;
    while(p<=n && m>0)
    {
        int min=INF , x=p;
        for(int i=p; i<=n; i++)
            if(a[i]<min)
            { min=a[i]; x=i;}
        if(x==p) 
            p++;
        else  
        {
            a[p]=a[p]^a[x];
            a[x]=a[p]^a[x];
            a[p]=a[p]^a[x];
            p++;
            m--;
        }
    }
    for(int i=1; i<=n; i++)
        printf("%d",a[i]);
    printf("\n");
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s%d",str+1,&m);
        if(m==0)
        {
            printf("%s\n",str+1);
            continue;
        }
        n=strlen(str+1);
        for(int i=1; i<=n; i++)
            a[i]=str[i]-'0';
        if(m>n) m=n;

        int min=INF,x=1;
        for(int i=1; i<=n; i++)
            if(a[i]!=0 && a[i]<min)
            { min=a[i]; x=i; }
        if(x==1)
        {
            solve(m);
            continue;
        }

        a[x]=a[x]^a[1];
        a[1]=a[x]^a[1];
        a[x]=a[x]^a[1];
        solve(--m);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/scau20110726/p/3030481.html