双向广搜+hash+康托展开 codevs 1225 八数码难题
codevs 1225 八数码难题
Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.
问题描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入初试状态,一行九个数字,空格用0表示
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)
283104765
4
详见试题
分类标签 Tags 点此展开
/*复杂题目模板加注解*/
# include <stdio.h>
# include <mem.h> # define MAXN ( + ) typedef struct
{
char a[];
}state; const int dir[][] = {{-,}, {,}, {,}, {,-}};
int fact[]; int front, rear;
state cur, nst; /* new state */
char vis[MAXN];
char dist[MAXN]; /* 求的是最短距离( < 100),可以用 char 类型 */
state Q[MAXN/]; void read(state *s);
int inversions(state s);
int cantor(state s);
void init_fact(void);
int bfs_d(state start, state goal); int main()
{
state start, goal; freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout); init_fact(); read(&start);/*指针引用*/
read(&goal); if (inversions(start)% == inversions(goal)%)/
{/*判断能不能到达最终状态,如果能达到最终状态的话,那么格子中的个数在后面有几个比他小的数的和的奇偶是不变的,无论怎么变换,可以用归纳推理证明*/
printf("%d\n", bfs_d(start, goal));
}
else puts("-1");/*找不到最终的状态*/ return ;
} int bfs_d(state start, state goal)
{
int i, x, y, nx, ny, ct, nt; memset(vis, , sizeof(vis));
memset(dist, , sizeof(dist)); front = ;
Q[front] = start;
rear = ;
Q[rear++] = goal;
vis[cantor(start)] = ; /* 1 表示从起始节点扩展得到 */
vis[cantor(goal)] = ; /* 2 表示从目标节点扩展得到 */ while (front < rear)
{
cur = Q[front++];
ct = cantor(cur);
for (i = ; cur.a[i] && i < ; ++i);/*找出0的位置*/
x = i / ;/*求出0所在的行数列数*/
y = i % ;
for (i = ; i < ; ++i)
{
nx = x + dir[i][];/*把0向四周扩展*/
ny = y + dir[i][];
if (nx>= && nx< && ny>= && ny<)
{
nst = cur;
nst.a[x*+y] = cur.a[nx*+ny];/*互换0的位置与对应元素的位置*/
nst.a[nx*+ny] = ;
if (!vis[nt = cantor(nst)])/*判断当前这个状态是否已经到过*/
{
Q[rear++] = nst;
/* foot[nt] = ct; */
dist[nt] = dist[ct] + ;
vis[nt] = vis[ct];/*转移扩展的方向*/
}
else if (vis[ct] != vis[nt])/*如果已经到过,就是两者变换的次数和加上最后一次变化*/
{/*这是双向广搜的精髓,判断两个点是从不同的方向转移来的*/
return + dist[nt] + dist[ct];
}
}
}
} return -;
} void read(state *s)
{
int i;
char c[]; for (i = ; i < ; ++i)
{
scanf("%s", c);
if (c[] == 'x') (*s).a[i] = ;
else (*s).a[i] = c[] - '';
}
} int inversions(state s)
{
char ch;
int i, j, ret; ret = ;
for (i = ; i < ; ++i)
{
if (s.a[i] == ) continue;
ch = s.a[i];
for (j = i+; j < ; ++j)
{
if (s.a[j] < ch && s.a[j] != )
++ret;
}
} return ret;
} int cantor(state s)/*康托展开应用于哈希表,处理排列问题是不会有冲突的,网上有证明,可以自己看*/
{
char ch;
int i, j, ret, cnt; ret = ;
for (i = ; i < ; ++i)
{
cnt = ;
ch = s.a[i];
for (j = i+; j < ; ++j)
{
if (s.a[j] < ch)
++cnt;
}
ret += cnt*fact[-i];
} return ret;
} void init_fact(void)
{
int i; fact[] = ;
for (i = ; i < ; ++i)
{
fact[i] = i * fact[i-];/*处理阶乘,整张图一共有9!种状态*/
}
}
本题题解:
#define N 3628800
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
struct state{
char a[];
};
queue<state>que;
int xx[]={,,,-};
int yy[]={,-,,};
int visit[N]={};
int fact[]={};
int dis[N]={};
void init_goal(state& goal)
{
goal.a[]='';goal.a[]='';goal.a[]='';
goal.a[]='';goal.a[]='';goal.a[]='';
goal.a[]='';goal.a[]='';goal.a[]='';
//goal.a="123804765";
//strcpy(goal.a,"123804765");
}
void in_fact()
{
fact[]=;
for(int i=;i<;++i)
fact[i]=i*fact[i-];
}
int cantor(state k)
{
int ret=;
for(int i=;i<;++i)
{
int cnt=;
char ch=k.a[i];
for(int j=i+;j<;++j)
if(ch>k.a[j]) cnt++;
ret+=cnt*fact[-i];
}
return ret;
}
int bfs(state begin,state goal)
{
que.push(begin);que.push(goal);
int k1=cantor(begin);
int k2=cantor(goal);
visit[k1]=;
visit[k2]=;
dis[k1]=;dis[k2]=;
while(!que.empty())
{
state fro=que.front();
int can_fro=cantor(fro);
que.pop();
int i;
for(i=;fro.a[i]!=''&&i<;++i);
int x=i/;
int y=i%;
for(int j=;j<;++j)
{
int nx=x+xx[j],ny=y+yy[j];
if(nx>=&&nx<&&ny>=&&ny<)
{
state now=fro;
now.a[*x+y]=fro.a[*nx+ny];
now.a[*nx+ny]='';
int kj=cantor(now);
if(!visit[kj])
{
que.push(now);
visit[kj]=visit[can_fro];/*转移是正向扩展还是逆向扩展*/
dis[kj]=dis[can_fro]+;
}
else if(visit[kj]!=visit[can_fro])
{/*这是双向广搜的精髓,必须用visit表示当前这个是同时由正反广搜扩展来的*/
return +dis[kj]+dis[can_fro];
}
}
}
}
}
int main()
{
state goal,begin;
init_goal(goal);
in_fact();
// scanf("%s",goal.a+1);
scanf("%s",begin.a);
printf("%d\n",bfs(begin,goal));
return ;
}
双向广搜+hash+康托展开 codevs 1225 八数码难题的更多相关文章
- Codevs 1225 八数码难题
1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Yours和zero在研究A*启发式算法.拿到一道经典的 ...
- poj 3131 Cubic Eight-Puzzle 双向广搜 Hash判重
挺不错的题目,很锻炼代码能力和调试能力~ 题意:初始格子状态固定,给你移动后格子的状态,问最少需要多少步能到达,如果步数大于30,输出-1. 由于单向搜索状态太多,搜到二十几就会爆了,所以应该想到双向 ...
- 习题:八数码难题(双向BFS)
八数码难题(wikioi1225) [题目描述] 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出 ...
- 双向广搜 codevs 3060 抓住那头奶牛
codevs 3060 抓住那头奶牛 USACO 时间限制: 1 s 空间限制: 16000 KB 题目等级 : 黄金 Gold 题目描述 Description 农夫约翰被告知一头逃跑奶牛 ...
- 万圣节后的早晨&&九数码游戏——双向广搜
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 ...
- 【双向广搜+逆序数优化】【HDU1043】【八数码】
HDU上的八数码 数据强的一B 首先:双向广搜 先处理正向搜索,再处理反向搜索,直至中途相遇 visit 和 队列都是独立的. 可以用一个过程来完成这2个操作,减少代码量.(一般还要个深度数组) 优化 ...
- nyoj 523 双向广搜
题目链接: http://acm.nyist.net/JudgeOnline/problem.php?pid=523 #include<iostream> #include<cstd ...
随机推荐
- 程序设计模式 —— State 状态模式
我应该如何阅读? 本文将使用优雅的文字风格来告诉你什么是状态模式. 注意: 1.在阅读本文之前请保证你已经掌控了 面对对象的思想与 多态的基本概念,否则将难以理解. 2.本文实现将用C++实现,你不一 ...
- [moka同学笔记]一、Yii2.0课程笔记(魏曦老师教程)
第一节 第二节 课程内容
- javascript --- 再谈词法分析
javascript代码是如何执行的呢,分为六个步骤(就像把大象装进冰箱总共分几步?): 第一步:载入第一个js代码段(注:script标签对内的代码或是引用js代码,这也说明js并不是一行一行(单纯 ...
- 为什么要选择Sublime Text3?
为什么要选择Sublime Text3? Sublime Text3 自动保存,打开图片 跨平台启动快!!!!多行游标,太好用. 插件,简直选不过来. 代码片段 VIM兼容模式 菜单栏基础功能介绍 F ...
- 在 SharePoint Server 2013 中配置建议和使用率事件类型
http://technet.microsoft.com/zh-cn/library/jj715889.aspx 适用于: SharePoint Server 2013 利用使用事件,您可以跟踪用户与 ...
- Sharepoint学习笔记—习题系列--70-573习题解析 -(Q35-Q39)
Question 35You have a custom Web Part that is deployed as a sandboxed solution.You need to ensure th ...
- IP 协议首部格式与其配套使用的四个协议(ARP,RARP,ICMP,IGMP)
目录 IP协议首部格式地址解析协议 ARP逆向地址解析协议 RARP网际控制报文协议 ICMP网际组管理协议IGMP IP 数据报首部 IP数据报首部格式: 最高位在左边,记为0 bit:最低位在右边 ...
- Spring中配置数据源的4种形式(转)
原文http://blog.csdn.net/orclight/article/details/8616103 不管采用何种持久化技术,都需要定义数据源.Spring中提供了4种不同形式的 ...
- Android官方多媒体API Mediacodec翻译(一)
因近期工作调整,关于Mediacodec部分的翻译会暂停,后续有时间一定补上,非常抱歉. 本文章为根据Android Mediacodec官方英文版的原创翻译,转载请注明出处:http://www.c ...
- C语言--static全局使用示例
前言:看到很多使用Objective-C开发IOS的大牛,有时候会使用static全局变量,相比之下,我却很少用这个,从而很少对其有着比较有实质意义的理解,甚至更别说运用它了. 今天,经过一番思考和自 ...