目录地址
前言
感谢黎某儿(划掉)教我这道题☆⌒(*^-゜)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);//输出第二段
}