题意:给一个数n,求一个比n小的最大的数,使得这个数把相邻的相同数合并之后,是一个回文数。
思路:dfs+剪枝。从高位到低位,从9~0尝试填数构造,如果可行就往下搜。dfs的过程也是构造的过程,需要剪枝,写两个函数,一个判断这个可能没构造完成的数是否可能构造出回文,另一个判断往后构造出来的数是否可能小于n,把不符合上面其中一种情况的分支剪掉。。。具体见代码。我写的时候是否可能构造出回文的判断就调试了很久。
#include<iostream>
#include<cmath>
#include<queue>
#include<vector>
#include<algorithm>
#include<string.h>
#include<cstdio>
using namespace std;
#define ll long long
int num[20];
int ans[20];
int len;
//判断这个可能尚未构造完成的数,有没有可能是回文数
bool judge(int* b,int pos){
if(pos==0)return 1;
int a[20];
memcpy(a,b,len*sizeof(int));
for(int i=1;i<len;i++){
int l=i,r=i;
do{
if(a[l]!=a[r]&&a[r]!=-1)break;
while(l>0&&a[l-1]!=-1&&a[l-1]==a[l])l--;
while(r<len-1&&a[r+1]!=-1&&a[r+1]==a[r])r++;
if(l>0&&r<len-1){
l--; r++;
}
}while(l!=0&&r!=len-1);
while(r<len-1&&(a[r]==a[r+1]||a[r+1]==-1))r++;
while(l>0&&a[l]==a[l-1])l--;
if(l==0&&r==len-1&&(a[l]==a[r]||a[r]==-1)){
return 1;
}
}
return 0;
}
//判断a是否小于b
bool lessthan(int* a,int* b){
for(int i=0;i<len;i++){
if(a[i]>b[i])return 0;
if(a[i]<b[i])return 1;
}
if(a[len-1]==b[len-1])return 0;
return 1;
}
bool dfs(int pos,int *a,bool flag){
if(pos==len){
for(int i=0;i<len;i++)ans[i]=a[i];
return 1;
}
int re[20];
for(int i=0;i<len;i++)re[i]=-1;
for(int i=0;i<pos;i++)re[i]=a[i];
int s=9;
if(!flag)s=num[pos];
for(int i=min(s,9);i>=0;i--){
if(!flag){
if(i<num[pos])flag=1;
}
re[pos]=i;
if(judge(re,pos)&&lessthan(re,num)){//只有可能是回文数且小于n的情况下才继续构造
if(dfs(pos+1,re,flag))return 1;
}
}
return 0;
}
int main(){
int t;
cin>>t;
while(t--){
ll n;
cin>>n;
if(n==1){
cout<<0<<endl;
continue;
}
ll tmp=n;
len=0;
while(tmp){
num[len++]=tmp%10;
tmp/=10;
}
for(int i=0;i<len;i++){
ans[i]=0;
}
reverse(num,num+len);
dfs(0,ans,0);
if(ans[0]==0){
for(int i=1;i<len;i++){
printf("9");
}printf("\n");
}else{
for(int i=0;i<len;i++){
printf("%d",ans[i]);
}printf("\n");
}
}
return 0;
}