万圣节后的早晨&&九数码游戏——双向广搜
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 ;
}
万圣节后的早晨&&九数码游戏——双向广搜的更多相关文章
- [ZJOI2005]九数码游戏
[ZJOI2005]九数码游戏 题目描述 输入输出格式 输入格式: 输入文件中包含三行三列九个数,同行的相邻两数用空格隔开,表示初始状态每个方格上的数字.初始状态不会是目标状态. 输出格式: 如果目标 ...
- 双向广搜+hash+康托展开 codevs 1225 八数码难题
codevs 1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Yours和zero在研究A*启 ...
- 【双向广搜+逆序数优化】【HDU1043】【八数码】
HDU上的八数码 数据强的一B 首先:双向广搜 先处理正向搜索,再处理反向搜索,直至中途相遇 visit 和 队列都是独立的. 可以用一个过程来完成这2个操作,减少代码量.(一般还要个深度数组) 优化 ...
- 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 ...
随机推荐
- Redis5.0:在这些场景使用,高效率还低成本!
很多大型电商网站.视频直播和游戏应用等,存在大规模数据访问,对数据查询效率要求高,且数据结构简单,不涉及太多关联查询. 这种场景使用Redis,在速度上对传统磁盘数据库有很大优势,能够有效减少数据库磁 ...
- 数据挖掘学习笔记——kaggle 数据预处理
预处理 1. 删除缺失值 a. 删除行即样本(对于样本如果输出变量存在缺失的则直接删除该行,因为无法用该样本训练) b. 删除列,即特征(采用这种删除方式,应保证训练集和验证集都应当删除相同的特征) ...
- 性能测试持续集成(Jenkins+Ant+Jmeter)
一.环境准备: 1.JDK:http://www.oracle.com/technetwork/java/javase/downloads/index.html 2.Jmeter:http://jme ...
- git blame 查看某行代码提交记录
1. 在当前git项目目录下执行 git blame -L 38,38 <filename> 例子: git blame -L 38,38 src/component/BarCode/i ...
- 安装VS的过程
软件工程学习到第三周,我们需要下载一个新的软件,用来进行软件测试.刚开始知道的时候觉得没甚么,不就是下个软件吗!有什么大不了的,分分钟搞定的事.可是想象很美好,现实很骨感.这是一个巨大的工作量呀,不仅 ...
- Alpha 冲刺(7/10)
队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 学习MSI.CUDA 试运行软件并调试 ...
- HDU 5286 How far away ? lca
题目链接: 题目 How far away ? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...
- UVALive 6913 I Want That Cake 博弈+dp
题目链接: http://acm.hust.edu.cn/vjudge/problem/96343 I Want That Cake Time Limit: 3000MS 64bit IO Forma ...
- IDEA + SSH OA 第一天(项目收获:Hibernate XML)
之前都是用工具逆向生成代码,很少写配置文件,今天试着使用,有几点需要注意 Cascade(级联): Cascade代表是否执行级联操作,Inverse代表是否由己方维护关系. Cascade属性的可能 ...
- 第一阶段android学习笔记
1.学习<第一行代码> 第一个android项目: 项目的注意点,如创建项目时包名具有唯一性,在做项目的时候要手动改成Project模式.还知道了引用字符串的两种方式. AS项目的三种依赖 ...