洛谷P1379 八数码难题

洛谷P1379 八数码难题

题意简述

洛谷

Solution

这是一道蓝题,蓝色是水的颜色,所以这是一道水题。

显然用一个structvector,再用一个queue进行bfs,用一个set记录是否在队列中,用一个map记录搜索到的目标状态需要的步数,我们就可以得到一个时间复杂度非常饱满类似于最短路的思想的bfs啦!

然而只有(37ptsdots)

这里考虑将structvector使用状态压缩进一个long long里面,暂时先把queue,setmap保留,你就有(97pts)了!(这难道不是水题吗)

坚持不开(O_2)的基本原则(虽然用了这么多STL开(O_2)应该会很爽),我们可以手写队列,setmap改成hash表,就可以通过这道题了!

image-20201201164034496

看上去很慢是不是……当然还有很多很多的优化,如双向宽搜(Astar),(IDAstardots)

所以这是一道很好的搜索优化练手题!

Code

状态压缩+手写队列+普通(bfs)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#define IL inline
#define re register
#define LL long long
#define ULL unsigned long long
#ifdef TH
#define debug printf("Now is %d
",__LINE__);
#else
#define debug
#endif
using namespace std;

template<class T>inline void read(T&x)
{
	char ch=getchar();
	int fu;
	while(!isdigit(ch)&&ch!='-') ch=getchar();
	if(ch=='-') fu=-1,ch=getchar();
	x=ch-'0';ch=getchar();
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	x*=fu;
}
inline int read()
{
	int x=0,fu=1;
	char ch=getchar();
	while(!isdigit(ch)&&ch!='-') ch=getchar();
	if(ch=='-') fu=-1,ch=getchar();
	x=ch-'0';ch=getchar();
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return x*fu;
}
int G[55];
template<class T>inline void write(T x)
{
	int g=0;
	if(x<0) x=-x,putchar('-');
	do{G[++g]=x%10;x/=10;}while(x);
	for(int i=g;i>=1;--i)putchar('0'+G[i]);putchar('
');
}

map<LL,int>dis;
set<LL>online;
//queue<LL>q;
LL q[1000000];int l,r;
const LL goal=123804765;
int dt[4][2]={1,0,-1,0,0,1,0,-1};
int now[3][3];
int i,j,way;
void bfs()
{
//	q.push(read());
	q[++r]=read();
	LL x,zx,zy,t,tx,ty;
	while(/*!q.empty()*/l<=r)
	{
//		t=x=q.front();
//		q.pop();
		t=x=q[l++];
		online.erase(x);
		if(x==goal)
		{
			write(dis[x]);
			return;
		}
		for(i=2;i>=0;i--)
		for(j=2;j>=0;j--)
		{
			now[i][j]=t%10;
			t/=10;
			if(now[i][j]==0) zx=i,zy=j;
		}
//		for(int i=0;i<3;i++)
//		{
//			for(int j=0;j<3;j++)
//			{
//				cout<<now[i][j]<<" ";
//			}
//			cout<<endl;
//		}
//		cout<<endl;
		for(way=0;way<4;way++)
		{
			tx=zx+dt[way][0];
			ty=zy+dt[way][1];
			if(tx<0||ty<0||tx>2||ty>2) continue;
			swap(now[tx][ty],now[zx][zy]);
			t=0;
			for(i=0;i<3;i++)
			for(j=0;j<3;j++)
			{
				t=t*10;
				t+=now[i][j];
			}
//			cout<<t<<endl;
			if(dis.find(t)==dis.end())
			{
				dis[t]=dis[x]+1;
//				q.push(t);
				q[++r]=t;
				online.insert(t);
			}
			else
			{
				if(dis[t]>dis[x]+1)
				{
					dis[t]=dis[x]+1;
					if(online.find(t)==online.end())
					{
						online.insert(t);
//						q.push(t);
						q[++r]=t;
					}
				}
			}
			swap(now[tx][ty],now[zx][zy]);
		}
	}
}

int main()
{
	bfs();
	
	return 0;
}
原文地址:https://www.cnblogs.com/send-off-a-friend/p/14069178.html