题目链接:Open the Lock
题意:就是给定两个4位数,起始,结束。问从起始数字到达结束数字 最少变换多少步,每个数 可以+1 / -1 或交换位置,都算做是一步。
单广,双广都用了,感觉双向BFS,太棒了,HDU的这个题双向BFS时间优化的太棒了
有图,有真相!
时间优化了近9倍。。。
PS:今天还学习一个sscanf函数,挺棒的
单搜的代码就不贴了,贴个双搜的
#include<cstdio>
#include <iostream>
#include<cstring>
#include <queue>
const int N = 10001; //因为是1-9 4位数 所以10000肯定够
using namespace std;
int vis[N];
int dis[N];
struct node
{
char a[5];
};
char st[5],en[5];
void BFS()
{
queue<node>q;
node f,t;
strcpy(f.a,st);
q.push(f);
int w,mm;
sscanf(f.a,"%d",&w);
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));
dis[w] = 0;
vis[w] = 1; // 从起点开始搜素的路线标记为1
strcpy(f.a,en);
q.push(f);
sscanf(f.a,"%d",&w);
dis[w] = 0;
vis[w] = 2; //从终点开始搜素的路线标记为2
while(!q.empty())
{
t = q.front();
q.pop();
for(int i = 0;i<3;i++)
{
if(i==0)
{
sscanf(t.a,"%d",&mm);
for(int j = 0;j<=3;j++)
{
f = t;
if(f.a[j]=='9') f.a[j] = '1';
else f.a[j] += 1;
sscanf(f.a,"%d",&w);
if(!vis[w])
{
vis[w] = vis[mm];
dis[w] = dis[mm] + 1;
q.push(f);
}
else if(vis[w]!=vis[mm])
{
printf("%d\n",dis[w]+dis[mm]+1);
return ;
}
}
}
else if(i==1)
{
sscanf(t.a,"%d",&mm);
for(int j = 0;j<=3;j++)
{
f = t;
if(f.a[j]=='1') f.a[j] = '9';
else f.a[j] -= 1;
sscanf(f.a,"%d",&w);
if(!vis[w])
{
vis[w] = vis[mm];
dis[w] = dis[mm] + 1;
q.push(f);
}
else if(vis[w]!=vis[mm])
{
printf("%d\n",dis[w]+dis[mm]+1);
return ;
}
}
}
else if(i==2)
{
sscanf(t.a,"%d",&mm);
for(int j = 0;j<3;j++)
{
f = t;
char g = f.a[j];
f.a[j] = f.a[j+1];
f.a[j+1] = g;
sscanf(f.a,"%d",&w);
if(!vis[w])
{
vis[w] = vis[mm];
dis[w] = dis[mm] + 1;
q.push(f);
}
else if(vis[w]!=vis[mm])
{
printf("%d\n",dis[w]+dis[mm]); // +1 /-1 两者相遇时都没变换状态,所以要加1步,而两数交换就是一步,所以不用加+
return ;
}
}
}
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s%s",st,en);
if(strcmp(st,en)==0)
printf("0\n");
else
BFS();
}
return 0;
}
测试数据,乱写的,以下都对了,应该就能AC
10
1234
6541
9
1111
1111
0
9999
9999
0
1111
1118
2
9911
1199
3
9512
3258
7
1238
9845
7
1111
2222
4
1111
6666
16
9559
9555
4
6554
4556
4