https://www.luogu.org/problemnew/show/P1778

https://www.luogu.org/problemnew/show/P2578

双向广搜。

有固定起点终点,过程可逆。

有时用于A*估价函数不好用的时候。

万圣节后的早晨

(由于鬼可以同时移动,估价函数不好设计)

优化:

1.预处理。

预处理每个可以到的位置的上下左右的块能否到达,建一个类似前向星的数组。

就可以很快地查询了。

2.每次枚举前1/2个鬼就可以判定当前的状态是否合法,可以减掉不少。

尽可能提前判断合法性,越快越好。

代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
typedef long long ll;
const int N=;
const int M=;
const int P=;
int mp[N][N];
int d1[M][M][M];
int d2[M][M][M];
int id[N][N];
int to[M][],sz[M];
int tot;
int n,m,k;
char s[N];
struct node{
int mem[];
void clear(){
mem[]=mem[]=mem[]=mem[]=;
}
void op(){
cout<<mem[]<<" "<<mem[]<<" "<<mem[]<<endl;
}
}st,nd;
node unzip(ll x){
//cout<<" unzip "<<x<<endl;
node ret;
ret.clear();
int cnt=;
while(x){
cnt++;
ret.mem[cnt]=x%P;
x/=P;
}
return ret;
}
int mv[][]={{,},{+,},{-,},{,+},{,-}};
int zip(node lp){
return lp.mem[]*P*P+lp.mem[]*P+lp.mem[];
}
queue<pair<int,int> >q1;
queue<pair<int,int> >q2;
bool bfs1(int dep){
while(!q1.empty()){
pair<int,int>now=q1.front();
if(now.second==dep) return false;
q1.pop();
//cout<<" haha "<<endl;
node kk=unzip(now.first);
//if(dep<10) kk.op();
node lp;lp.clear();
for(int i=;i<=sz[kk.mem[]];i++){
lp.mem[]=to[kk.mem[]][i]; for(int j=;j<=sz[kk.mem[]];j++){
lp.mem[]=to[kk.mem[]][j];
if(lp.mem[]==lp.mem[]) continue;
if(lp.mem[]==kk.mem[]&&lp.mem[]==kk.mem[]) continue;
//cout<<"lp "<<endl;lp.op();
for(int p=;p<=sz[kk.mem[]];p++){
lp.mem[]=to[kk.mem[]][p];
if(lp.mem[]){
if(lp.mem[]==lp.mem[]) continue;
if(lp.mem[]==lp.mem[]) continue;
if(lp.mem[]==kk.mem[]&&lp.mem[]==kk.mem[]) continue;
if(lp.mem[]==kk.mem[]&&lp.mem[]==kk.mem[]) continue;
}
if(d2[lp.mem[]][lp.mem[]][lp.mem[]]!=-) return true;
else if(d1[lp.mem[]][lp.mem[]][lp.mem[]]==-){
d1[lp.mem[]][lp.mem[]][lp.mem[]]=dep;
q1.push(make_pair(zip(lp),now.second+));
}
}
}
}
}
return false;
}
bool bfs2(int dep){
while(!q2.empty()){
pair<int,int>now=q2.front();
if(now.second==dep) return false;
q2.pop();
node kk=unzip(now.first);
node lp;lp.clear();
for(int i=;i<=sz[kk.mem[]];i++){
lp.mem[]=to[kk.mem[]][i];
for(int j=;j<=sz[kk.mem[]];j++){
lp.mem[]=to[kk.mem[]][j];
if(lp.mem[]==lp.mem[]) continue;
if(lp.mem[]==kk.mem[]&&lp.mem[]==kk.mem[]) continue;
for(int p=;p<=sz[kk.mem[]];p++){
lp.mem[]=to[kk.mem[]][p];
if(lp.mem[]){
if(lp.mem[]==lp.mem[]) continue;
if(lp.mem[]==lp.mem[]) continue;
if(lp.mem[]==kk.mem[]&&lp.mem[]==kk.mem[]) continue;
if(lp.mem[]==kk.mem[]&&lp.mem[]==kk.mem[]) continue;
}
if(d1[lp.mem[]][lp.mem[]][lp.mem[]]!=-) return true;
else if(d2[lp.mem[]][lp.mem[]][lp.mem[]]==-){
d2[lp.mem[]][lp.mem[]][lp.mem[]]=dep;
q2.push(make_pair(zip(lp),now.second+));
}
}
}
}
}
return false;
}
void clear(){
tot=;
memset(mp,,sizeof mp);
memset(d1,-,sizeof d1);
memset(d2,-,sizeof d2);
memset(id,,sizeof id);
memset(to,,sizeof to);
memset(sz,,sizeof sz);
st.clear();
nd.clear();
while(!q1.empty())q1.pop();
while(!q2.empty())q2.pop();
}
int main(){
while(){
cin>>m>>n>>k;
if(n==&&m==&&k==) break;
clear();
char ch;while((ch=getchar())||)if(ch=='\n')break;
for(int i=;i<=n;i++){
int lp=;
while((s[lp]=getchar())||) if(s[lp++]=='\n')break;
for(int j=;j<=m;j++){
if(s[j-]==' '){
mp[i][j]=;
id[i][j]=++tot;
}
else if(s[j-]=='#'){
mp[i][j]=;
}
else if(s[j-]>='a'&&s[j-]<='z'){
id[i][j]=++tot;
st.mem[s[j-]-'a'+]=tot;
}
else if(s[j-]>='A'&&s[j-]<='Z'){
id[i][j]=++tot;
nd.mem[s[j-]-'A'+]=tot;
}
}
} for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
if(!id[i][j]) continue;
//cout<<i<<" "<<j<<endl;
for(int p=;p<;p++){
int dx=i+mv[p][];
int dy=j+mv[p][];
if(dx<||dx>n) continue;
if(dy<||dy>m) continue;
if(mp[dx][dy]) continue;
sz[id[i][j]]++;
to[id[i][j]][sz[id[i][j]]]=id[dx][dy];
}
}
} //cout<<"after "<<endl;
id[][]=;
sz[]++;
to[][]=;
//st.op();
q1.push(make_pair(zip(st),));
//cout<<zip(st)<<endl;
d1[st.mem[]][st.mem[]][st.mem[]]=;
q2.push(make_pair(zip(nd),));
d2[nd.mem[]][nd.mem[]][nd.mem[]]=;
int ans=;
int b1=,b2=;
while(){
ans++;
//if(ans<10) cout<<ans<<endl;
if(bfs1(++b1)) break;
ans++;
if(bfs2(++b2)) break;
}
cout<<ans<<endl;
}
return ;
}

九数码游戏

(由于顺时针转,变化太大,估价函数也不好设计。)

(当然这个题可以直接bfs,但是双向广搜在luogu上快了50倍)其实要注意的就是一点。

因为双向广搜的另一边是一个逆过程,所以,顺时针变成逆时针,向右变成向左。

值得注意。

至于方案,根据hash表中元素的单一性,而且有SPJ,所以,记录一下每个状态的前驱即可。

代码:

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=;
const int M=;
const int mo=1e5;
const int ED=;
struct ha{
int val[M];
int nxt[M],hd[mo];
int pre[M];
int cnt;
void ins(int x,int from){
cnt++;
val[cnt]=x;pre[cnt]=from;
int pos=x%mo;
nxt[cnt]=hd[pos];
hd[pos]=cnt;
}
bool query(int x){
int pos=x%mo;
for(int i=hd[pos];i;i=nxt[i]){
if(val[i]==x) return ;
}
return ;
}
int fin(int x){
int pos=x%mo;
for(int i=hd[pos];i;i=nxt[i]){
if(val[i]==x) return pre[i];
}
return ;
}
}HA1,HA2;
queue<pair<int,int> >q1;
queue<pair<int,int> >q2;
int st,nd;
int sta[],top;
int num1,num2;
int mp[][];
void op(int x){
for(int i=;i>=;i--)
for(int j=;j>=;j--)
mp[i][j]=x%,x/=;
for(int i=;i<=;i++){
for(int j=;j<=;j++){
printf("%d ",mp[i][j]);
}puts("");
}
puts("");
}
int mv1(int x){
for(int i=;i>=;i--)
for(int j=;j>=;j--)
mp[i][j]=x%,x/=;
int tmp=mp[][];
mp[][]=mp[][];mp[][]=mp[][];mp[][]=mp[][];mp[][]=mp[][];
mp[][]=mp[][];mp[][]=mp[][];mp[][]=mp[][];mp[][]=tmp;
int ret=;
for(int i=;i<=;i++){
for(int j=;j<=;j++){
ret=ret*+mp[i][j];
}
}return ret;
}
int mv2(int x){
for(int i=;i>=;i--)
for(int j=;j>=;j--)
mp[i][j]=x%,x/=;
int tmp=mp[][];
mp[][]=mp[][];mp[][]=mp[][];mp[][]=tmp;
int ret=;
for(int i=;i<=;i++){
for(int j=;j<=;j++){
ret=ret*+mp[i][j];
}
}return ret;
}
int mv3(int x){
for(int i=;i>=;i--)
for(int j=;j>=;j--)
mp[i][j]=x%,x/=;
int tmp=mp[][];
mp[][]=mp[][];mp[][]=mp[][];mp[][]=mp[][];mp[][]=mp[][];
mp[][]=mp[][];mp[][]=mp[][];mp[][]=mp[][];mp[][]=tmp;
int ret=;
for(int i=;i<=;i++){
for(int j=;j<=;j++){
ret=ret*+mp[i][j];
}
}return ret;
}
int mv4(int x){
for(int i=;i>=;i--)
for(int j=;j>=;j--)
mp[i][j]=x%,x/=;
int tmp=mp[][];
mp[][]=mp[][];mp[][]=mp[][];mp[][]=tmp;
int ret=;
for(int i=;i<=;i++){
for(int j=;j<=;j++){
ret=ret*+mp[i][j];
}
}return ret;
}
int bfs1(int dp){
while(!q1.empty()){
pair<int,int> lp=q1.front();
if(lp.second==dp) return ;
q1.pop();
int now=lp.first;
int t1=mv1(now);
if(HA2.query(t1)){
num1=now;
num2=t1;
return ;
}
else if(!HA1.query(t1)){
HA1.ins(t1,now);
q1.push(make_pair(t1,lp.second+));
} int t2=mv2(now);
if(HA2.query(t2)){
num1=now;
num2=t2;
return ;
}
else if(!HA1.query(t2)){
HA1.ins(t2,now);
q1.push(make_pair(t2,lp.second+));
}
}
return ;
}
int bfs2(int dp){
while(!q2.empty()){
pair<int,int> lp=q2.front();
if(lp.second==dp) return ;
q2.pop();
int now=lp.first;
int t1=mv3(now);
if(HA1.query(t1)){
num2=now;
num1=t1;
return ;
}
else if(!HA2.query(t1)){
HA2.ins(t1,now);
q2.push(make_pair(t1,lp.second+));
} int t2=mv4(now);
if(HA1.query(t2)){
num2=now;
num1=t2;
return ;
}
else if(!HA2.query(t2)){
HA2.ins(t2,now);
q2.push(make_pair(t2,lp.second+));
}
}
return ;
}
int main(){
int t;
for(int i=;i<=;i++)scanf("%d",&t),st=st*+t;
nd=ED;
if(st==nd){
printf("");
op(st);
}
HA2.ins(nd,);
HA1.ins(st,);
q1.push(make_pair(st,));
q2.push(make_pair(nd,));
int ans=;
int b1=,b2=;
while(){
ans++;
int d1=bfs1(++b1);
if(d1==) break;
ans++;
int d2=bfs2(++b2);
if(d2==) break;
if(d1==&&d2==) {
printf("UNSOLVABLE");return ;
}
}
//over
printf("%d\n",ans);
top=;
while(num1!=){
sta[++top]=num1;
num1=HA1.fin(num1);
}
while(top)op(sta[top--]);
while(num2!=){
op(num2);
num2=HA2.fin(num2);
}
return ;
}

万圣节后的早晨&&九数码游戏——双向广搜的更多相关文章

  1. [ZJOI2005]九数码游戏

    [ZJOI2005]九数码游戏 题目描述 输入输出格式 输入格式: 输入文件中包含三行三列九个数,同行的相邻两数用空格隔开,表示初始状态每个方格上的数字.初始状态不会是目标状态. 输出格式: 如果目标 ...

  2. 双向广搜+hash+康托展开 codevs 1225 八数码难题

    codevs 1225 八数码难题  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond   题目描述 Description Yours和zero在研究A*启 ...

  3. 【双向广搜+逆序数优化】【HDU1043】【八数码】

    HDU上的八数码 数据强的一B 首先:双向广搜 先处理正向搜索,再处理反向搜索,直至中途相遇 visit 和 队列都是独立的. 可以用一个过程来完成这2个操作,减少代码量.(一般还要个深度数组) 优化 ...

  4. HDU--杭电--1195--Open the Lock--深搜--都用双向广搜,弱爆了,看题了没?语文没过关吧?暴力深搜难道我会害羞?

    这个题我看了,都是推荐的神马双向广搜,难道这个深搜你们都木有发现?还是特意留个机会给我装逼? Open the Lock Time Limit: 2000/1000 MS (Java/Others)  ...

  5. 双向广搜 POJ 3126 Prime Path

      POJ 3126  Prime Path Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 16204   Accepted ...

  6. 双向广搜 codevs 3060 抓住那头奶牛

    codevs 3060 抓住那头奶牛 USACO  时间限制: 1 s  空间限制: 16000 KB  题目等级 : 黄金 Gold   题目描述 Description 农夫约翰被告知一头逃跑奶牛 ...

  7. nyoj 523 双向广搜

    题目链接: http://acm.nyist.net/JudgeOnline/problem.php?pid=523 #include<iostream> #include<cstd ...

  8. poj 3131 Cubic Eight-Puzzle 双向广搜 Hash判重

    挺不错的题目,很锻炼代码能力和调试能力~ 题意:初始格子状态固定,给你移动后格子的状态,问最少需要多少步能到达,如果步数大于30,输出-1. 由于单向搜索状态太多,搜到二十几就会爆了,所以应该想到双向 ...

  9. Eleven puzzle_hdu_3095(双向广搜).java

    Eleven puzzle Time Limit: 20000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

随机推荐

  1. HTML从入门到放弃

    一.HTML 简介 链接:https://www.cnblogs.com/baishuchao/articles/9179920.html 二.HTML 基础 链接:https://www.cnblo ...

  2. IDE看代码,挺好

    初学编程的时候总是收到各种警告:“刚学习编程千万不要用IDE,否则会有xxxxxx的后果”.现在工作后发现使用IDE可以方便编写和查看代码,对于较大的项目来说有很多代码,代码之间的关系也比较复杂,ID ...

  3. 7个Node.js的Web框架

    NodeJS也就是Node,是众所周知的使用javascript构建Web应用框架,它启动一个服务器非常简单,如下: var http = require('http'); http.createSe ...

  4. python常用快捷键

    最重要的快捷键1. ctrl+shift+A:万能命令行2. shift两次:查看资源文件 新建工程第一步操作1. module设置把空包分层去掉,compact empty middle packa ...

  5. python基础知识-01-编码输入输出变量

    python其他知识目录 名词解释: 编辑器 ide 程序员 操作系统 ASCAII码 unicode utf-8 浅谈CPU.内存.硬盘之间的关系 操作系统及Python解释器工作原理讲解 关于编译 ...

  6. redis rdb aof比较

    Redis中数据存储模式有2种:cache-only,persistence; cache-only即只做为“缓存”服务,不持久数据,数据在服务终止后将消失,此模式下也将不存在“数据恢复”的手段,是一 ...

  7. Python中用字符串导入module

    在Python中,无法通过字符串来导入一个module文件: import "string" # Error x = "string" import x # 不 ...

  8. Bracket Sequences Concatenation Problem括号序列拼接问题(栈+map+思维)

    A bracket(括号) sequence is a string containing only characters "(" and ")".A regu ...

  9. 六周psp

    本周psp 本周进度条 代码累积折线图 博文字数累积折线图 饼状图

  10. Python:列表操作总结

    一.创建一个列表 只要把逗号分隔的不同数据项使用方括号括起来即可 list1=['physics','chemistry',1997,2000] list2=[1,2,3,4,5,6,7] [注]:1 ...