HDU 1195 Open the Lock (双向广搜)

题意:给你初始4个数字和目标4个数字,问是否能由初始经过变换到目标数字;

变换规则:每个数字可以加1(9+1=1)或减1(1-1=9),或交换相邻的数字(最左和最右不是相邻的)。

双向广搜:分别对初始和目标数字进行广搜,vis数组用1和2标记两种已搜索的数字,用mp数组记录状态的步数。

当从前往后搜可以到达2或从后往前搜可以到达1状态则就可以了。。。

#include<stdio.h>
#include<string.h>
#include<string>
#include<queue>
#include<map>
#include<iostream>
#include<algorithm>
using namespace std;

struct node
{
	int a[4];
	int step;
}s,e;
int vis[10001];//标记当前状态是否有走过(从前往后走为1,从后往前走为2,没有走过为0)
int mp[10001];//标记走到当前状态的步数
int get_num(int c[])
{
	int n=0;
	for(int i=0;i<4;i++)
	{
		n*=10;
		n+=c[i];
	}
	return n;
}
int bfs()
{
	memset(vis,0,sizeof(vis));
	memset(mp,0,sizeof(mp));
	queue<node>p,q;
	int tmp;
	tmp=get_num(s.a);
	vis[tmp]=1;
	tmp=get_num(e.a);
	vis[tmp]=2;

	node u,v;
	p.push(s);
	q.push(e);
	while(!q.empty()||!p.empty())
	{
		if(!p.empty())
		{
			u=p.front();
			p.pop();
			for(int i=0;i<4;i++)
			{
				v=u;
				v.a[i]=u.a[i]+1;//+1
				if(v.a[i]==10)
					v.a[i]=1;
				tmp=get_num(v.a);
				if(vis[tmp]==0)//从前往后没有走过
				{
					v.step=u.step+1;
					mp[tmp]=v.step;//标记走到当前状态的步数
					vis[tmp]=1;
					p.push(v);
				}
				else if(vis[tmp]==2)//从前往后与从后往前有交叉
					return u.step+mp[tmp]+1;
				v.a[i]=u.a[i]-1;//-1
				if(v.a[i]==0)
					v.a[i]=9;
				tmp=get_num(v.a);
				if(vis[tmp]==0)
				{
					v.step=u.step+1;
					mp[tmp]=v.step;
					vis[tmp]=1;
					p.push(v);
				}
				else if(vis[tmp]==2)
					return u.step+mp[tmp]+1;
			}
			for(int i=0;i<3;i++)//交换
			{
				v=u;
				int k=v.a[i];
				v.a[i]=v.a[i+1];
				v.a[i+1]=k;
				tmp=get_num(v.a);
				if(vis[tmp]==0)
				{
					v.step=u.step+1;
					mp[tmp]=v.step;
					vis[tmp]=1;
					p.push(v);
				}
				else if(vis[tmp]==2)
					return u.step+mp[tmp]+1;
			}

		}
		if(!q.empty())
		{
			u=q.front();
			q.pop();
			for(int i=0;i<4;i++)
			{
				v=u;
				v.a[i]=u.a[i]+1;
				if(v.a[i]==10)
					v.a[i]=1;
				tmp=get_num(v.a);
				if(vis[tmp]==0)
				{
					v.step=u.step+1;
					mp[tmp]=v.step;
					vis[tmp]=2;
					q.push(v);
				}
				else if(vis[tmp]==1)//从后往前与从前往后哟交叉
					return u.step+mp[tmp]+1;

				v.a[i]=u.a[i]-1;
				if(v.a[i]==0)
					v.a[i]=9;
				tmp=get_num(v.a);
				if(vis[tmp]==0)
				{
					v.step=u.step+1;
					mp[tmp]=v.step;
					vis[tmp]=2;
					q.push(v);
				}
				else if(vis[tmp]==1)
					return u.step+mp[tmp]+1;
			}
			for(int i=0;i<3;i++)
			{
				v=u;
				int k=v.a[i];
				v.a[i]=v.a[i+1];
				v.a[i+1]=k;
				tmp=get_num(v.a);
				if(vis[tmp]==0)
				{
					v.step=u.step+1;
					mp[tmp]=v.step;
					vis[tmp]=2;
					q.push(v);
				}
				else if(vis[tmp]==1)
					return u.step+mp[tmp]+1;
			}
		}
	}
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		char s1[10],s2[10];
		scanf("%s%s",s1,s2);
		for(int i=0;i<4;i++)
			s.a[i]=s1[i]-'0';
		for(int i=0;i<4;i++)
			e.a[i]=s2[i]-'0';
		s.step=0;
		e.step=0;
		printf("%d\n",bfs());
	}
	return 0;
}
/*
99
1221
1212
*/

HDU 1195 Open the Lock (双向广搜)

时间: 2024-10-08 19:35:02

HDU 1195 Open the Lock (双向广搜)的相关文章

HDU 1195 Open the Lock 双向BFS

题目链接:Open the Lock 题意:就是给定两个4位数,起始,结束.问从起始数字到达结束数字 最少变换多少步,每个数 可以+1 / -1 或交换位置,都算做是一步. 单广,双广都用了,感觉双向BFS,太棒了,HDU的这个题双向BFS时间优化的太棒了 有图,有真相! 时间优化了近9倍... PS:今天还学习一个sscanf函数,挺棒的 单搜的代码就不贴了,贴个双搜的 #include<cstdio> #include <iostream> #include<cstrin

hdu 1195:Open the Lock(暴力BFS广搜)

mediaxyz是一位研究ffmpeg有三年的高人了,这几天一直在折腾ffmpeg中的x264,就是不知道该如何控制码率,主要是参数太多,也不知道该如何设置,在 google上search了一下,这方面的介绍为0,那就找mediaxyz请教请教吧,这些可都是经验,非常宝贵! 以下是与mediaxyz在QQ上聊天的记录,只有一部分,因为QQ把之前的谈话删除了,但基本上精髓都可这里了. mediaxyz 23:40:26你说的qsable是c->global_quality吧 Leon 23:40:

HDU 3085 Nightmare Ⅱ (双向广搜)

题意:有M,G两人和鬼魂(Z)在n*m的方格内,M每秒走3步,G每秒走一步,鬼魂每秒走2步,问是否能 不遇到鬼魂下两人相遇,鬼魂可以穿墙(X),人不可以.初始鬼魂有2个. #include<stdio.h> #include<string.h> #include<string> #include<queue> #include<map> #include<iostream> #include<algorithm> #def

HDU 1401 Solitaire (双向广搜)

题意:在二维8*8的方格,给定4个初始点和4个最终点,问在8步内是否能从初始点走到最终点, 规则:每个点能上下左右移动,若4个方向已经有点则可以跳到下一个点. 双向广搜:同时对初始点和最终点广搜4步,对每一步记录状态,初始点为'1',最终点为'2', 若在限定时间内初始点的状态能到达'2',或最终点的状态能到达'1',则为YES!要记得排序.. #include<stdio.h> #include<string.h> #include<queue> #include&l

双向广搜

双向广搜 (2011-08-31 16:45:24)   Eight    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 讲到双向广搜,那就不能不讲经典的八数码问题,有人说不做此题人生不完整 . 所谓双向广搜,就是初始结点向目标结点和目标结点向初始结点同时扩展,直至在两个扩展方向上出现同一个结点,搜索结束.它适用的问题是,扩展结点较多,而目标结点又处在深沉,如果采用单纯的广搜解题,搜索量巨大,搜索速度慢是可想而知的,同时往往也会出现内存空

codevs 1225:八数码难题【双向广搜】

这里是传送门 这道题用普通BFS是可以做的,但是很明显没得过,效率太低了.效率更高的算法A*和双向广搜都可取,这写一下双向广搜的. 注意题目中的判重很重要,可以转化成九位数用hash来解决这个问题. #include <set> #include <string> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define

nyoj 523 双向广搜

题目链接: http://acm.nyist.net/JudgeOnline/problem.php?pid=523 #include<iostream> #include<cstdio> #include<queue> using namespace std; /* 用普通搜索TLE,已知起点和终点,可以考虑双向广搜或A*算法加速搜索 双向广搜,一个方向从出发点向终点搜索,一个方向从终点向出发点搜索,搜索到相同的结点时,即找到最短路径. */ const int N

双向广搜 POJ 3126 Prime Path

POJ 3126  Prime Path Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 16204   Accepted: 9153 Description The ministers of the cabinet were quite upset by the message from the Chief of Security stating that they would all have to change th

双向广搜 开始!!!

先简单的了解一下,双向广搜很好理解,就是从两端一起搜,如果遇到之前已经搜到过的状态,就相当于已经有解了,这样就会节省一半的内存和时间,并且代码复杂度并不高.只需要在正常的基础上多开一个域,保存这个点是从起始状态还是终止状态拓展的.当然双向广搜中状态的判断需要一些技巧,现在还没有总结出什么. 八数码问题: 很经典的一种双向广搜,因为只有九个数,所以用康托展开作为hash值.拓展时,如果这个hash值已经访问过,就判断,如果是两条路过来的就输出,否则就继续做:对于没有访问过的hash值就可以添加到队