题目链接: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
HDU 1195 Open the Lock 双向BFS
时间: 2024-10-08 00:10:43