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;
}