【双向广搜+逆序数优化】【HDU1043】【八数码】
HDU上的八数码 数据强的一B
首先:双向广搜
先处理正向搜索,再处理反向搜索,直至中途相遇
visit 和 队列都是独立的。 可以用一个过程来完成这2个操作,减少代码量。(一般还要个深度数组)
优化效率很强
逆序数优化
在忽略空格的情况,会发现 空格无论怎么变,1-8的排列的逆序数始终要为偶数,才能有解(空格无视)
而且证明得出:如果满足逆序条件,必定有解!
拓展
N*N的情况
N×N的棋盘,N为奇数时,与八数码问题相同。
N为偶数时,空格每上下移动一次,奇偶性改变。称空格位置所在的行到目标空格所在的行步数为空格的距离(不计左右距离),若两个状态的可相互到达,则有,两个状态的逆序奇偶性相同且空格距离为偶数,或者,逆序奇偶性不同且空格距离为奇数数。否则不能。
>推广到三维N×N×N
其实,三维的结论和二维的结论是一样的。
考虑左右移动空格,逆序不变;同一层上下移动空格,跨过N-1个格子;上下层移动空格,跨过N^2-1个格子。
当N为奇数时,N-1和N^2-1均为偶数,也就是任意移动空格逆序奇偶性不变。那么逆序奇偶性相同的两个状态可相互到达。
当N为偶数时,N-1和N^2-1均为奇数,也就是令空格位置到目标状态空格位置的y z方向的距离之和,称为空格距离。若空格距离为偶数,两个逆序奇偶性相同的状态可相互到达;若空格距离为奇数,两个逆序奇偶性不同的状态可相互到达。
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <queue>
#define oo 0x13131313
using namespace std;
struct node
{
int operator[](int index) const {
return A[index];
}
int& operator[](int index) {
return A[index];
}
int A[10];
int xnum;
int deep;
int Contor;
void JSContor()
{
int temp=0,p=1;
for(int i=8;i>=0;i--)
{
int tot=0;
for(int j=0;j<i;j++)
if(A[j]<A[i]) tot++;
temp+=(A[i]-tot-1)*p;
p=p*(9-i);
}
Contor=temp+1;
}
};
int visit[2][370000];
int dist[2][370000];
int DEEP[2][370000];
int dANS[2][370000];
char f[4]={'u','d','l','r'};
queue <node> Q[2];
node start;
node End; char AAA[20];
void init()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
}
void input()
{
memset(visit,0,sizeof(visit));
for(int i=0;i<9;i++)
{
if(AAA[i]=='x')
{
start[i]=9;
start.xnum=i;
}
else start[i]=AAA[i]-'0';
End[i]=i+1;
}
End.xnum=8;
End.deep=0;
start.deep=0;
}
void csh()
{
while(Q[0].empty()!=1) Q[0].pop();
start.JSContor();
visit[0][start.Contor]=1;
Q[0].push(start); while(Q[1].empty()!=1) Q[1].pop();
End.JSContor();
visit[1][End.Contor]=1;
Q[1].push(End);
}
int GAN(int pos)
{
node s,t;
s=Q[pos].front();
Q[pos].pop();
if(visit[pos^1][s.Contor]==1) {
return s.Contor;
}
s.deep++;
//
t=s;
if(((t.xnum)/3)!=0)
{
swap(t[t.xnum],t[t.xnum-3]);
t.xnum=t.xnum-3;
t.JSContor();
if(visit[pos][t.Contor]==0)
{
Q[pos].push(t);
visit[pos][t.Contor]=1;
dist[pos][t.Contor]=s.Contor;
dANS[pos][t.Contor]=0;
DEEP[pos][t.Contor]=t.deep;
}
} //
t=s;
if(((t.xnum)/3)!=2)
{
swap(t[t.xnum],t[t.xnum+3]);
t.xnum=t.xnum+3;
t.JSContor();
if(visit[pos][t.Contor]==0)
{
Q[pos].push(t);
visit[pos][t.Contor]=1;
dist[pos][t.Contor]=s.Contor;
dANS[pos][t.Contor]=1;
DEEP[pos][t.Contor]=t.deep;
}
}
//
t=s;
if(t.xnum%3!=0)
{
swap(t[t.xnum],t[t.xnum-1]);
t.xnum--;
t.JSContor();
if(visit[pos][t.Contor]==0)
{
Q[pos].push(t);
visit[pos][t.Contor]=1;
dist[pos][t.Contor]=s.Contor;
dANS[pos][t.Contor]=2;
DEEP[pos][t.Contor]=t.deep;
}
}
//
t=s;
if((t.xnum+1)%3!=0)
{
swap(t[t.xnum],t[t.xnum+1]);
t.xnum++;
t.JSContor();
if(visit[pos][t.Contor]==0)
{
Q[pos].push(t);
visit[pos][t.Contor]=1;
dist[pos][t.Contor]=s.Contor;
dANS[pos][t.Contor]=3;
DEEP[pos][t.Contor]=t.deep;
}
}
return 0;
}
void twobfs()
{
void print(int ok1);
csh();
int ok1=0,ok2=0;
while(Q[0].empty()!=1&&Q[1].empty()!=1)
{
ok1=GAN(0);
if(ok1!=0) break;
ok2=GAN(1);
if(ok2!=0) {ok1=ok2;break;}
}
print(ok1);
}
char ANS[20];
void print(int ok1)
{
int tot=1;
for(int p=ok1;p!=start.Contor;p=dist[0][p])
{
ANS[tot]=f[dANS[0][p]];
tot++;
}
for(int i=tot-1;i>=1;i--)
printf("%c",ANS[i]);
tot=1;
for(int p=ok1;p!=End.Contor;p=dist[1][p])
{
ANS[tot]=f[dANS[1][p]^1];
tot++;
}
for(int i=1;i<tot;i++)
printf("%c",ANS[i]);
printf("\n");
}
int OK=1;
int JZyj()
{
int tot1=0;
for(int i=0;i<=8;i++)
for(int j=0;j<i;j++)
{
if(start[i]!=9&&start[j]!=9)
if(start[i]<start[j]) tot1++;
}
if(tot1%2==0) return 1;
else return 0;
}
int main()
{
//init();
char c;
while(scanf("%c %c %c %c %c %c %c %c %c\n",&AAA[0],&AAA[1],&AAA[2],&AAA[3],&AAA[4],&AAA[5],&AAA[6],&AAA[7],&AAA[8])!=EOF)
{
input();
if( JZyj())
twobfs();
else printf("unsolvable\n");
}
}
利用预处理稍微压缩一下BFS后(BFS多移动一般都可以用预处理压缩)
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <queue>
#define oo 0x13131313
using namespace std;
struct node
{
int operator[](int index) const {
return A[index];
}
int& operator[](int index) {
return A[index];
}
int A[10];
int xnum;
int deep;
int Contor;
void JSContor()
{
int temp=0,p=1;
for(int i=8;i>=0;i--)
{
int tot=0;
for(int j=0;j<i;j++)
if(A[j]<A[i]) tot++;
temp+=(A[i]-tot-1)*p;
p=p*(9-i);
}
Contor=temp+1;
}
};
int visit[2][370000];
int dist[2][370000];
int DEEP[2][370000];
int dANS[2][370000];
char f[4]={'u','d','l','r'};
int fx[5]={-1,+1,0,0};
int fy[5]={0,0,-1,+1};
queue <node> Q[2];
node start;
node End; char AAA[20];
void init()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
}
void input()
{
memset(visit,0,sizeof(visit));
for(int i=0;i<9;i++)
{
if(AAA[i]=='x')
{
start[i]=9;
start.xnum=i;
}
else start[i]=AAA[i]-'0';
End[i]=i+1;
}
End.xnum=8;
End.deep=0;
start.deep=0;
}
void csh()
{
while(Q[0].empty()!=1) Q[0].pop();
start.JSContor();
visit[0][start.Contor]=1;
Q[0].push(start); while(Q[1].empty()!=1) Q[1].pop();
End.JSContor();
visit[1][End.Contor]=1;
Q[1].push(End);
}
int GAN(int pos)
{
node s,t;
int x,y,p;
s=Q[pos].front();
Q[pos].pop();
if(visit[pos^1][s.Contor]==1) {
return s.Contor;
}
s.deep++;
x=s.xnum/3;y=s.xnum%3;
for(int i=0;i<=3;i++)
{
t=s;
if(x+fx[i]<=2&&x+fx[i]>=0&&y+fy[i]<=2&&y+fy[i]>=0)
{
p=(x+fx[i])*3+y+fy[i];
swap(t[t.xnum],t[p]);
t.xnum=p;
t.JSContor();
if(visit[pos][t.Contor]==0)
{
Q[pos].push(t);
visit[pos][t.Contor]=1;
dist[pos][t.Contor]=s.Contor;
dANS[pos][t.Contor]=i;
DEEP[pos][t.Contor]=t.deep;
}
}
}
return 0;
}
void twobfs()
{
void print(int ok1);
csh();
int ok1=0,ok2=0;
while(Q[0].empty()!=1&&Q[1].empty()!=1)
{
ok1=GAN(0);
if(ok1!=0) break;
ok2=GAN(1);
if(ok2!=0) {ok1=ok2;break;}
}
print(ok1);
}
char ANS[20];
void print(int ok1)
{
int tot=1;
for(int p=ok1;p!=start.Contor;p=dist[0][p])
{
ANS[tot]=f[dANS[0][p]];
tot++;
}
for(int i=tot-1;i>=1;i--)
printf("%c",ANS[i]);
tot=1;
for(int p=ok1;p!=End.Contor;p=dist[1][p])
{
ANS[tot]=f[dANS[1][p]^1];
tot++;
}
for(int i=1;i<tot;i++)
printf("%c",ANS[i]);
printf("\n");
}
int OK=1;
int JZyj()
{
int tot1=0;
for(int i=0;i<=8;i++)
for(int j=0;j<i;j++)
{
if(start[i]!=9&&start[j]!=9)
if(start[i]<start[j]) tot1++;
}
if(tot1%2==0) return 1;
else return 0;
}
int main()
{
//init();
char c;
while(scanf("%c %c %c %c %c %c %c %c %c\n",&AAA[0],&AAA[1],&AAA[2],&AAA[3],&AAA[4],&AAA[5],&AAA[6],&AAA[7],&AAA[8])!=EOF)
{
input();
if( JZyj())
twobfs();
else printf("unsolvable\n");
}
}
【双向广搜+逆序数优化】【HDU1043】【八数码】的更多相关文章
- 双向广搜+hash+康托展开 codevs 1225 八数码难题
codevs 1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Yours和zero在研究A*启 ...
- 万圣节后的早晨&&九数码游戏——双向广搜
https://www.luogu.org/problemnew/show/P1778 https://www.luogu.org/problemnew/show/P2578 双向广搜. 有固定起点终 ...
- HDU--杭电--1195--Open the Lock--深搜--都用双向广搜,弱爆了,看题了没?语文没过关吧?暴力深搜难道我会害羞?
这个题我看了,都是推荐的神马双向广搜,难道这个深搜你们都木有发现?还是特意留个机会给我装逼? Open the Lock Time Limit: 2000/1000 MS (Java/Others) ...
- 双向广搜 POJ 3126 Prime Path
POJ 3126 Prime Path Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 16204 Accepted ...
- 双向广搜 codevs 3060 抓住那头奶牛
codevs 3060 抓住那头奶牛 USACO 时间限制: 1 s 空间限制: 16000 KB 题目等级 : 黄金 Gold 题目描述 Description 农夫约翰被告知一头逃跑奶牛 ...
- nyoj 523 双向广搜
题目链接: http://acm.nyist.net/JudgeOnline/problem.php?pid=523 #include<iostream> #include<cstd ...
- poj 3131 Cubic Eight-Puzzle 双向广搜 Hash判重
挺不错的题目,很锻炼代码能力和调试能力~ 题意:初始格子状态固定,给你移动后格子的状态,问最少需要多少步能到达,如果步数大于30,输出-1. 由于单向搜索状态太多,搜到二十几就会爆了,所以应该想到双向 ...
- Eleven puzzle_hdu_3095(双向广搜).java
Eleven puzzle Time Limit: 20000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- HDU1043 八数码(BFS + 打表)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 , 康托展开 + BFS + 打表. 经典八数码问题,传说此题不做人生不完整,关于八数码的八境界 ...
随机推荐
- _declspec(dllexport)与_declspec(dllimport)
__declspec(dllexport)2009-03-04 17:25 我相信写WIN32程序的人,做过DLL,都会很清楚__declspec(dllexport)的作用,它就是为了省掉在DEF文 ...
- UML_用例图
用例图主要用来描述"用户.需求.系统功能单元"之间的关系.它展示了一个外部用户能够观察到的系统功能模型图. [用途]:帮助开发团队以一种可视化的方式理解系统的功能需求. 用例图所包 ...
- POJ 3321 Apple Tree (DFS + 树状数组)
题意: 一棵苹果树有N个分叉,编号1---N(根的编号为1),每个分叉只能有一颗苹果或者没有苹果. 现在有两种操作: 1.某个分叉上的苹果从有变无或者从无边有. 2.需要统计以某个分叉为根节点时,它的 ...
- python内置函数(2)-递归与迭代
这篇文章简单介绍了迭代和递归的概念.两者的区别 什么是迭代: 迭代是重复反馈过程的活动,其目的通常是为了接近并达到所需的目标或结果.每一次对过程的重复被称为一次“迭代”,而每一次迭代得到的结果会被用来 ...
- Number Sequence(kmp)
Number Sequence Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...
- UVA 10131 Is Bigger Smarter?(DP)
Some people think that the bigger an elephant is, the smarter it is. To disprove this, you want to t ...
- 使用bat批处理命令打包maven项目
使用批处理命令打包java项目,给我们发布war或jar包带来了很大的便利,附上代码,以作留存. ::huap-parent ::common-parent ::market-parent ::cus ...
- iOS开发之基于parse的登录注册
基本上现在的每一款app都有登录功能.那也就少不了注册,找回密码等操作. 今天要说的就是初学者可以使用parse做为后台的服务器来进行一系列的操作,等以后工作的时候可以用公司的服务器. 注册用户 Bm ...
- .NET自动更新
asp.net b/s就是布置在服务器的.你这个是要单机版的更新机制,博客园里面好几篇文章说这事呢. http://www.cnblogs.com/cnsharp/archive/2013/04/11 ...
- Majority Element,Majority Element II
一:Majority Element Given an array of size n, find the majority element. The majority element is the ...