zoukankan      html  css  js  c++  java
  • SSLZYC 2574 Closest

    题目大意:
    这里写图片描述


    思路:

    思路一:贪心
    一开始我的想法是利用贪心,能选择更小的数就选择更小的数。如果最终无法选择,就输出0。这样就能保证答案最优(也就是与A的差的绝对值最小)。

    贪心代码:

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    char A[101],B[101];
    int a[101],b[3][11],n,big[101],small[101];
    
    int main()
    {
        freopen("closest.in","r",stdin);
        freopen("closest.out","w",stdout);
        scanf("%s%s",&A,&B);
        n=strlen(A);    
        for (int i=1;i<=n;i++)
        {
            a[i]=A[i-1]-48;
            b[1][B[i-1]-48]++;
            b[2][B[i-1]-48]++;  //桶排
        }  
        int b_ok=1;
        int s_ok=1;
        for (int i=1;i<=n;i++)  //枚举每一位数
        {
            if (b_ok==1)
            {
                int k=a[i];
                while (b[1][k]==0&&k<=9) k++;  //贪心
                if (k>9) b_ok=0;
                else if (k>a[i])  //如果已经有一位数比A大了,那就可以直接输出(无论后面的数多小,都与大小无关)
                {
                    big[i]=k;
                    b[1][k]--;
                    int l=0;
                    b_ok=2;
                    for (int j=i+1;j<=n;j++)
                    {
                        while(b[1][l]<=0) l++;
                        b[1][l]--;
                        big[j]=l;
                    }
                }
                else  //如果相等
                {
                    big[i]=k;
                    b[1][k]--;
                }
            }
            if (s_ok==1)  //同上
            {
                int k=a[i];
                while (b[2][k]==0&&k>=0) k--;
                if (k<0||(k==0&&i==1)) s_ok=0;
                else if (k<a[i])
                {
                    small[i]=k;
                    b[2][k]--;
                    int l=9;
                    s_ok=2;
                    for (int j=i+1;j<=n;j++)
                    {
                        while(b[2][l]<=0) l--;
                        b[2][l]--;
                        small[j]=l;
                    }
                }
                else 
                {
                    small[i]=k;
                    b[2][k]--;
                }
            }
        }
        if (b_ok==0) printf("0");
        else
         for (int i=1;i<=n;i++) printf("%d",big[i]);
        printf("\n");
        if (s_ok==0) puts("0");
        else
        {
            for (int i=1;i<=n+1;i++)
            {
                if (small[i]!=a[i]) break;
                if (i>n) 
                {
                    puts("0");
                    return 0;
                }
            }
            for (int i=1;i<=n;i++) printf("%d",small[i]);
        }
        return 0;
    }

    先别抄代码,这个贪心是错!误!的!

    如果遇到下面这组数据:
    123456789012345678901234567890
    100700000000200000030000040056

    贪心的输出是:
    0
    123456700000000000000000000000

    标准输出是:
    123457000000000000000000000006
    123456700000000000000000000000

    思路二:DFS
    在贪心的基础上加上DFS的回溯,就能把所有可能都找出,就不用害怕答案错啦~~~


    代码:

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    char A[101],B[101];
    int a[101],b[3][11],n,big[101],small[101],c[101],b_ok,s_ok;
    
    void dfs1(int x)  //搜索≥A的最小的数
    {
        if (a[x-1]<big[x-1]&&x!=1)  //和贪心一样,特殊判断
        {
            int j=0;
            for (int k=x;k<=n;k++)
            {
                while (b[1][j]<=0) j++;
                big[k]=j;
                b[1][j]--;
            }
            for (int i=1;i<=n;i++)
             printf("%d",big[i]);
            b_ok=1;
            return;
        }
        if (x>n)  //已经搜索完毕
        {
            for (int i=1;i<=n;i++)
             printf("%d",big[i]);
            b_ok=1;
            return;
        }
        for (int i=a[x];i<=9;i++)  //枚举第x个数字
        {
            if (b[1][i]>0)   //还有这个数字
            {
                b[1][i]--;
                big[x]=i;
                dfs1(x+1);  //继续DFS
                big[x]=0;
                b[1][i]++;
            }
            if (b_ok==1) return;
        }
    }
    
    void dfs2(int x)//搜索<A的最小的数
    {
        if (c[x-1]>small[x-1]&&x!=1)  //同上
        {
            int j=9;
            for (int k=x;k<=n;k++)
            {
                while (b[2][j]<=0) j--;
                small[k]=j;
                b[2][j]--;
            }
            for (int i=1;i<=n;i++)
             printf("%d",small[i]);
            s_ok=1;
            return;
        }
        if (x>n)  //依旧同上
        {
            for (int i=1;i<=n;i++)
             printf("%d",small[i]);
            s_ok=1;
            return;
        }
        for (int i=c[x];i>=0;i--)  //还是同上
        {
            if (i==0&&x==1) return;
            if (b[2][i]>0) 
            {
                b[2][i]--;
                small[x]=i;
                dfs2(x+1);  //继续DFS
                small[x]=0;
                b[2][i]++;
            }
            if (s_ok==1) return;
        }
    }
    
    int main()
    {
        scanf("%s%s",&A,&B);
        n=strlen(A);    
        for (int i=1;i<=n;i++)
        {
            a[i]=A[i-1]-48;
            c[i]=a[i];
            b[1][B[i-1]-48]++;
            b[2][B[i-1]-48]++;  //桶排
        }  
        int i=n;
        c[n]--;
        while (c[i]<0)  //将<A转化成≤A-1,高精
        {
            c[i]+=10;
            i--;
            c[i]--;
        }
    
        dfs1(1);
        if (b_ok==0) printf("0");
        printf("\n");
        dfs2(1);
        if (s_ok==0) printf("0");
        return 0;
    }
  • 相关阅读:
    1 绪论
    3.4 向量空间及其子空间的的基与维数
    3.3 极大线性无关组以及&向量的秩
    3.2 线性相关与线性无关的向量组
    3.1 n维向量空间及其子空间
    2.6 拉普拉斯定理
    2.5 克拉默法则
    2.4 行列式按行(列)展开
    2.3 行列式的性质
    2.2 n阶行列式的定义
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/9313100.html
Copyright © 2011-2022 走看看