题意:一个长度为5的串,初始为12345,有三种变化方式:
1、交换任意相邻的两个数,无次数限制
2、任意一位上的数字加1,超过10对10取模,限制3次。
3、任意一位上的数字*2,超过10对10取模,限制2次。
现在给你一个串,求12345变成这个串的最小次数。如果无法变成,则输出-1。
思路:
经典bfs,开三维记录一下12345变成数i、用j次2操作、k次3操作的最小次数,然后记忆一下就可以O(1)查询了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int n,m,k;
int go;
int vis[100010][4][3];
bool us[100010];
int jc[10];
void bfs()
{
memset(us,0,sizeof(us));
jc[6]=1;
for(int i=5;i>=0;i--)
jc[i]=jc[i+1]*10;
for(int i=0;i<=99999;i++)
for(int j=0;j<4;j++)
for(int k=0;k<3;k++)
vis[i][j][k]=inf;
queue<int>q;
q.push(12345);
us[12345]=1;
vis[12345][0][0]=0;
while(!q.empty())
{
//cout<<"*";
int a=q.front();q.pop();
us[a]=0;
for(int i=1;i<5;i++)
{
int j=i+1;
int x=(a%jc[i])/jc[i+1];
int y=(a%jc[j])/jc[j+1];
//cout<<x<<y<<endl;
if(x==y) continue;
int tmp=a-x*jc[i+1]-y*jc[j+1];
tmp+=x*jc[j+1]+y*jc[i+1];
//cout<<a<<" "<<tmp<<endl;
int fg=0;
for(int k=0;k<4;k++)
for(int l=0;l<3;l++)
{
if(vis[tmp][k][l]>vis[a][k][l]+1)
{
vis[tmp][k][l]=vis[a][k][l]+1;
fg=1;
}
}
if(fg&&!us[tmp]) {
us[tmp]=1;
q.push(tmp);
}
}
for(int i=1;i<6;i++)
{
int x=(a%jc[i])/jc[i+1];
int tmp=a-x*jc[i+1]+((x+1)%10)*jc[i+1];
if(tmp==a) continue;
int fg=0;
for(int k=1;k<4;k++)
for(int l=0;l<3;l++)
if(vis[tmp][k][l]>vis[a][k-1][l]+1)
{
vis[tmp][k][l]=vis[a][k-1][l]+1;
fg=1;
}
if(fg&&!us[tmp]) {
us[tmp]=1;
q.push(tmp);
}
}
for(int i=1;i<6;i++)
{
int x=(a%jc[i])/jc[i+1];
int tmp=a-x*jc[i+1]+((x*2)%10)*jc[i+1];
if(tmp==a) continue;
int fg=0;
for(int k=0;k<4;k++)
for(int l=1;l<3;l++)
if(vis[tmp][k][l]>vis[a][k][l-1]+1)
{
vis[tmp][k][l]=vis[a][k][l-1]+1;
fg=1;
}
if(fg&&!us[tmp]) {
us[tmp]=1;
q.push(tmp);
}
}
}
}
int main()
{
bfs();
int x;
while(scanf("%d",&x)!=EOF)
{
int ma=inf;
for(int i=0;i<4;i++)
for(int j=0;j<3;j++)
ma=min(ma,vis[x][i][j]);
if(ma==inf) puts("-1");
else printf("%d\n",ma);
}
return 0;
}