题目大意:
给出A与B,都是n位数(n<=60),需要找到最近的靠近A的n位数,使得它们的十进制表示是B中所有数字的某个排列。
假如A=3022并且B=1232,用B的数字我们可以获得以下的4位数字:1223, 1232, 1322, 2123, 2132, 2213, 2231, 2312, 2321, 3122, 3212和3221。最小的比A大或者和A相等的数,且用B中的数字组成的是3122,并且最大的严格比A小的数是2321。
解题思路:
快排+纯模拟
然后先判断最小的是否大于或等于A,如果大于或等于A则没有小于A的,直接输出最小的和0就好
还有判断最大的是否小于A,如果小于A则没有大于或等于A的,直接输出0和最大的就好
若上面两个都不成立,则都存在,现在开始用一组数据解释我的思路
数据:
3000203
4562454
用一个桶统计每个数字在B中出现的次数
0 1 2 3 4 5 6 7 8 9
0 0 1 0 3 2 1 0 0 0
判断(上面讲了的两个判断),
发现两种都存在,就开始找,先输出最小的大于或等于A的,就找最大的
a[1]是3,找比它大的在B中存在的最小的,找到是4,就用4当b[1],交换当前的b[1],b[2]也是,若b[i]>a[i],则后面的可以不找,因为b[i]>a[i]后面无论怎么排都不会使A>B,所以直接sort后面的,从小到大排序就可以了
然后找小于A的最大的a[1]是3,找比它小的最大的,自然就是2,然后发现b[i]
源程序:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
char cs[101];
int a[101],b[101],c[101],s[11],n;
bool cmp(int x,int y)
//快排判断,从小到大排(完全可以省略)
{
return x<y;
}
bool cmp1(int x,int y)//快盘判断,从大到小排
{
return x>y;
}
int main()
{
//freopen("closest.in","r",stdin);
//freopen("closest.out","w",stdout);
cin>>cs;
n=strlen(cs);
for (int i=0;i<n;i++)
a[i+1]=cs[i]-48;
cin>>cs;
for (int i=0;i<n;i++)
b[i+1]=cs[i]-48;//读入处理不多说
sort(b+1,b+n+1,cmp);//从这里开始
int f=0;
int k=1;
while (!b[k]) k++;
int l=1;
int y=n;
swap(b[k],b[1]);
int x=0;
for (int i=1;i<=n;i++)
if (b[i]==a[i]) x++;
else if(b[i]>a[i]) {x=n;break;}
else if (b[i]<a[i]) {x=0;break;}
if (x==n)
f=-1,swap(b[k],b[1]);
else if (b[l]<a[1]) f=1;
else if (b[1]==a[1]) while (b[l]==a[l]&&l<n)
{
l++;
if (b[l]>a[l])
{f=0;break;} else f=1;
}
else f=0;
if (f==0)
{
for (int i=1;i<=n;i++)
printf("%d",b[i]);
printf("\n0");
return 0;
}
else if (f==-1)
{
printf("%d",b[k]);
for (int i=1;i<=n;i++)
if (i!=k)
printf("%d",b[i]);
printf("\n0");
return 0;
}
sort(b+1,b+n+1,cmp1);
f=0;
k=1;
l=k;
if (b[l]>a[1]) f=1;
else if (b[1]==a[1]) while (b[l]==a[l]&&l<n)
{
l++;
if (b[l]<=a[l])
{f=0;break;} else f=1;
}
else f=0;
if (f==0)
{
printf("0\n");
for (int i=1;i<=n;i++)
printf("%d",b[i]);
return 0;
}//到这里都是上面所说的两种判断
sort(b+1,b+n+1,cmp);//找大于或等于A的最小的
for (int i=0;i<=10;i++)
for (int j=1;j<=n;j++)
if (b[j]==i)
s[i]++; //存入桶
l=1;
k=a[l];
while (!s[k]&&k<10)
k++;
sort(b+1,b+n+1,cmp1);
int p=1;
while (b[p]!=k)
p++;
swap(b[1],b[p]);//交换
x=0;
for (int i=1;i<=n;i++)
if (b[i]==a[i]) x++;
else if(b[i]>a[i]) {x=n;break;}
else if (b[i]<a[i]) {x=0;break;}
if (x!=n)
k++;
x=0;
p=1;
while (b[p]!=k)
p++;
swap(b[1],b[p]);
s[k]--;
p=1;
bool hh=0;
if (a[l]<k)
sort(b+2,b+n+1,cmp);
//如果第一位就大于A的第一位,后面无论如何都可以,所以直接快排
else
{
hh=0;
sort(b+l+1,b+n+1,cmp1);
//否则,先快排一次后面的,然后一次一次纠正
while (l<n)
{
l++;
p=l;
k=a[l];
while (!s[k]&&k<10)
k++;
if (k==10)‘
//这里就是已经找不到了,但是前面判断过一定有,
//由此得知,前面有错
//所以这里纠正一下
{
hh=0;
for (int o=l-1;o>=1;o--)
if (hh) break;
else
for (int h=1;h<=l;h++)
if (o!=h&&b[h]>b[o])
{swap(b[h],b[o]);hh=1;
sort(b+o+1,b+n+1,cmp);
//纠正了之后必定大于,直接排序
break;
}
}
while (b[p]!=k&&p<n)
p++;
if (a[l]<=b[p])
{
swap(b[l],b[p]);
if(a[l]<b[p]&&!s[a[l]])
{
sort(b+l+1,b+n+1,cmp);
break;
}
s[k]--;
//这些操作解题思路就有讲过,这里就不讲了
}
p=l;
if (hh)
break;
//如果已经纠正过了,就找到了正解,退出就好了
}
}
for (int i=1;i<=n;i++)
printf("%d",b[i]),c[i]=b[i];//输出
sort(c+1,c+n+1,cmp1);
//从大到小排序(我也不知道为什么)
for (int i=0;i<=10;i++)
s[i]=0;
for (int i=0;i<=10;i++)
for (int j=1;j<=n;j++)
if (c[j]==i)
s[i]++;
l=1;
k=a[l];
while (!s[k]&&k>1)
k--;
sort(c+1,c+n+1,cmp);
p=1;
while (c[p]!=k&&p<n)
p++;
swap(c[1],c[p]);
for (int i=1;i<=n;i++)
if (c[i]==a[i]) x++;
else if(c[i]<a[i]) {x=0;break;}
else if (c[i]>a[i]) {x=n;break;}
if (x==n)
k--;
x=0;
p=1;
while (c[p]!=k)
p++;
swap(c[1],c[p]);
s[k]--;
p=1;
if (a[l]>k)
sort(c+2,c+n+1,cmp1);
else
{
hh=0;
sort(c+l+1,c+n+1,cmp);
while (l<n)
{
l++;
p=l;
k=a[l];
while (!s[k]&&k>-1)
k--;
if (k==-1)
{
hh=0;
for (int o=l-1;o>=1;o--)
if (hh) break;
else
for (int h=1;h<=l;h++)
if (o!=h&&c[h]<c[o])
{swap(c[h],c[o]);hh=1;
sort(c+o+1,c+n+1,cmp1);
break;
}
}
while (c[p]!=k&&p<n)
p++;
if (a[l]>=c[p])
{
swap(c[l],c[p]);
if (a[l]>c[p]&&!s[a[l]])
{
sort(c+l+1,c+n+1,cmp1);
break;
}
s[k]--;
}
p=l;
}
}//这里则是相反
for (int i=1;i<=n;i++)
if (c[i]==a[i]) x++;
//这里要纠正,因为上面我是等于也要那啥
if (x==n)
{
l=n;
int q=c[n];
while (c[n]==c[l])
l--;
swap(c[n],c[l]);
}//然后如果完全相等纠正一波
puts("");
for (int i=1;i<=n;i++)
printf("%d",c[i]);//愉快输出
}