CDOJ 414 Eight Puzzle 搜索 BFS

八数码是非常经典的搜索题,不过这道有点不一样:

There are multiple test cases.

操蛋的是数据量灰常灰常多!

出题人还写了句:Any violent algorithm may gain TLE. So a smart method is expected.

喵喵喵?

总之直接每个数据bfs是妥妥的TLE。

不过我们开动脑筋想一想,发现这道题可以打表。

打表???

没错,关键就在于终止状态是一样的。

所以我们只需要最终的状态开始BFS,遍历每一个状态,存下需要的步数(注意访问不到的状态),然后就可以愉快地打表了~

每次只需bfs一遍!

至于状态怎么存,自行搜索康托展开。

代码很久以前写的,改了很多遍,大概比较丑,酌情看吧。。。


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define M 1000000
#define P 23333
#define ed 46233
using namespace std;

struct node
{
	int num[10],x,step;
}st,fm;

char s[10];
queue <node> q;
int ppow[15],ans,book[1000010],sth;
bool vis[1000010];
int re;

int haha(node t)
{
	long long sum=0;
	for (int i=1;i<=9;i++)
	{
		int tot=0;
		for (int j=i+1;j<=9;j++)
		{
			if (t.num[i]>t.num[j]) tot++;
		}
		sum+=tot*ppow[9-i];
	}
	return (int)sum;
}

void rebfs()
{
	q.push(fm); vis[haha(fm)]=true;
	while (!q.empty())
	{
		node now=q.front(); q.pop();
		/*if (now.step==2) {printf(" %d %d\n",now.x,haha(now));
		for (int i=1;i<=9;i++)
		{
			printf("%d ",now.num[i]);
		}
		printf("\n");}*/
		int hanow=haha(now);
		if (!book[hanow]) book[hanow]=now.step;
		if (hanow==sth)
		{
			ans=now.step;
			book[haha(st)]=ans;
			return;
		}
		if (now.x>3)
		{
			node nn=now;
			nn.x=now.x-3;
			nn.num[now.x]=now.num[nn.x];
			nn.num[nn.x]=0;
			nn.step=now.step+1;
			int th=haha(nn);
			if (!vis[th])
			{
				vis[th]=true;
				q.push(nn);
			}
		}
		if (now.x<7)
		{
			node nn=now;
			nn.x=now.x+3;
			nn.num[now.x]=now.num[nn.x];
			nn.num[nn.x]=0;
			nn.step=now.step+1;
			int th=haha(nn);
			if (!vis[th])
			{
				vis[th]=true;
				q.push(nn);
			}
		}
		if (now.x%3!=1)
		{
			node nn=now;
			nn.x=now.x-1;
			nn.num[now.x]=now.num[nn.x];
			nn.num[nn.x]=0;
			nn.step=now.step+1;
			int th=haha(nn);
			if (!vis[th])
			{
				vis[th]=true;
				q.push(nn);
			}
		}
		if (now.x%3!=0)
		{
			node nn=now;
			nn.x=now.x+1;
			nn.num[now.x]=now.num[nn.x];
			nn.num[nn.x]=0;
			nn.step=now.step+1;
			int th=haha(nn);
			if (!vis[th])
			{
				vis[th]=true;
				q.push(nn);
			}
		}
	}
}

void init()
{
	while (!q.empty()) q.pop();
	memset(vis,0,sizeof(vis));
	ans=-1;
	re=5;
}

int main()
{
	ppow[0]=1;
	for (int i=1;i<=10;i++)
	{
		ppow[i]=(ppow[i-1]*i)%M;
	}
	/*node t;
	for (int i=1;i<=8;i++)
	{
		t.num[i]=i;
	}
	t.num[9]=0;
	printf("%d",haha(t));*/
	for (int i=1;i<=8;i++)
	{
		fm.num[i]=i;
	}
	fm.num[9]=0; fm.x=9;
	for (int i=1;i<=6;i++)
	{
		st.num[i]=i;
	}
	st.num[7]=8; st.num[8]=7; fm.x=9;
	sth=haha(st);
	rebfs();
	//printf("%d",ans);
	while (scanf("%c",&s[1])!=-1)
	{
		init();
		for (int i=2;i<=9;i++)
		{
			getchar();
			scanf("%c",&s[i]);
		}
		getchar();
		for (int i=1;i<=9;i++)
		{
			if (s[i]!='x') st.num[i]=s[i]-'0';
			else st.num[i]=0,st.x=i;
		}
		sth=haha(st);
		//bfs();
		ans=book[sth];
		if (ans==0)
		{
			if (sth!=ed) printf("unsolvable\n");
			else printf("0\n");
		}
		else printf("%d\n",ans);
		/*for (int i=0;i<=46233;i++)
		{
			printf("%d ",book[i]);
		}*/
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cjj490168650

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值