题解:模拟退火,进行位置交换的尝试,通过判断最高位是否相等缩小区间。
#include<bits/stdc++.h>
#define ll long long int
using namespace std;
ll pow(int a,ll b)
{
ll sum=1;
for(int i=0;i<b;i++)
{
sum*=a;
}
return sum;
}
double random(int l,int r)
{
int a=rand(),b=rand()+1;
double ans=(double)a/b;
while(ans>r||ans<l)//可以取到l和r,加上等号则无法取到 l和r
{
a=rand(),b=rand()+1;
ans=(double)a/b;
}
return ans;
}
int main()
{
srand((unsigned)time(NULL));
ll a,b,MAX,k=0; //MAX最大值,k为a的位数
cin>>a>>b;
MAX=0;
ll m=a;
while(m)//计算a的位数
{
m=m/10;
k++;
}
k++;//需要取1~k位
double T=100000,p=0.9999;//模拟退火的初始温度T,退火率p
if(k==2)//只有一位数的时候,直接输出
{
cout<<a<<endl;
}
else
{
while(T>1e-6)
{
ll a1=rand()%k,a2=rand()%k;
if((a1==a2||a1==0||a2==0)&&k>2) continue;//防止与自身交换,并且剩余不确定的位数多余1
if(a2>a1)//保证a1>a2
{
ll temp=a1;
a1=a2;
a2=temp;
}
ll k1,k2;//交换第a1和a2位
k1=a%pow(10,a1)/pow(10,a1-1)*pow(10,a2-1);
k2=a%pow(10,a2)/pow(10,a2-1)*pow(10,a1-1);
a=a/pow(10,a1)*pow(10,a1)+a%pow(10,a1-1)/pow(10,a2)*pow(10,a2)+a%pow(10,a1-1)%pow(10,a2-1);
a=a+k1+k2;//交换后的a
if(a>MAX&&a<=b)//贪心,选最优
{
MAX=a;
if(a/pow(10,k-2)==b/pow(10,k-2)&&k>2)//如果最高为相同,则不再交换最高位
{
k--;
}
}
else
{
double t=exp(-T);
if(t<random(0,1))//如果找到比当前更差的解,以一定概率接受该解,并且这个概率会越来越小
{
a=a;
}
else
{
a=MAX;
}
}
T=T*p;//退火
}
cout<<MAX<<endl;
}
return 0;
}