【2018.3.10】模拟赛之一-ssl2574Closest【深搜】

目录地址

前言

感谢黎某儿(划掉)教我这道题☆⌒(*^-゜)v。


正题

给出两个n位数A,B。我们需要找到两个最近的靠近A的n位数(第一个比A大或与A相等,第二个严格比A小),使得它们的十进制表示是B中所有数字的某个排列。


输入输出(需要自取)

Input

输入文件closest.in包含2行:
第1行为一个正整数A。
第1行为一个正整数B。
(A,B均为n位的正整数)

Output

输出文件closest.out共有2行。
第一行:最小的不比A小的n位数,没有前导0,包含B中的所有字符,以某一顺序排列。如果这样的数不存在,那么输出0。
第二行:最大的比A小的n位数,没有前导0,包含B中的所有字符,以某一顺序排列。如果这样的数不存在,那么输出0。

Sample Input

输入样例1

3075
6604

输入样例2

3000203
4562454

Sample Output

输出样例1

4066
0

输出样例2

4244556
2655444


解题思路

B用桶存,然后分两段输出,一段是相等的和第一个不相等(大的或小的),第二段是将桶剩下的输出(从大到小或从小到大),然后用dfs更正。


代码

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int c[61],f[10],t[10],p[61];
char read;
int n,maxn,mark;
bool flag,flag2,ok;
void dfs(int i)//深搜
{
    if (i>n)//全部等于的情况
    {
        flag=true;
        ok=true;
        for (int j=1;j<=n;j++) printf("%d",p[j]);
        return;
    }
    flag2=false;
    for (int j=c[i];j<=9;j++)
    {
        if (f[j]>0)
        {
            p[i]=j;
            f[j]--;
            flag2=true;
            if (j>c[i])//找到一个了
            {
                flag=true;
                break;
            }
            dfs(i+1);//深搜
            if (ok) return;
            f[j]++;//回溯
        }
    }
    if (flag)
    {
        for (int j=1;j<=i;j++) printf("%d",p[j]);//输出第一部分
        ok=true;
        return;
    }
    if (!flag2)//找不到了
    {
        return;
    }
}
void dfs2(int i)//相仿,看上面↑
{
    if (i>n)
    {
        ok=true;
        return;
    }
    flag2=false;
    for (int j=c[i];j>=0;j--)
    {
        if (t[j]>0 && (i!=1 || j!=0))
        {
            p[i]=j;
            t[j]--;
            flag2=true;
            if (j<c[i])
            {
                flag=true;
                break;
            }
            dfs2(i+1);
            if (ok) return;
        }
    }
    if (flag)
    {
        for (int j=1;j<=i;j++) printf("%d",p[j]);
        ok=true;
        return;
    }
    if (!flag2)
    {
        return;
    }
}
int main()
{
    while ((read=getchar())!='\n')
    {
        n++;
        c[n]=read-48;//输入
    }
    for (int i=1;i<=n;i++) {cin>>read;t[read-48]++;f[read-48]++;}//输入
    flag=false;ok=false;
    dfs(1);//搜
    if (!flag && !flag2) printf("0");//找不到
    else for (int i=0;i<=9;i++)
           for (int j=1;j<=f[i];j++)
             printf("%d",i);//输出第二段
    printf("\n");
    flag=false;
    dfs2(1);
    if (!flag && !flag2) printf("0");
    else if(flag2 && !flag)
    {
        if (prev_permutation(p+1,p+1+n))//如果连段可以全部相等就输出上一个排列
          for (int j=1;j<=n;j++) printf("%d",p[j]);
    }
    else for (int i=9;i>=0;i--)
           for (int j=1;j<=t[i];j++)
             printf("%d",i);//输出第二段
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值