SSL-ZYC 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;
}
posted @ 2018-03-10 15:09  全OI最菜  阅读(81)  评论(0编辑  收藏  举报