hdu 1043(经典搜索)
题意:
给你一个初始的图,然后每次输入一个图,要求移动x最小的步数达到和初始图一样,输出路径
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8
9 x 10 12 9 10 x 12 9 10 11 12 9 10 11 12
13 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x
r-> d-> r->
好像有很多中方法解决这个问题:八数码的八个境界
①bfs + 康托展开+打表 /* 其他的还不会,有空去试试 - -
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <algorithm>
typedef long long ll;
using namespace std; const int MAXN=362900;//最多是9!/2
int fac[]= {1,1,2,6,24,120,720,5040,40320,362880}; //康拖展开判重
// 0!1!2!3! 4! 5! 6! 7! 8! 9!
bool vis[MAXN];//标记
char path[MAXN][40];//记录路径
int cantor(int s[])//康拖展开求该序列的hash值
{
int sum=0;
for(int i=0; i<9; i++)
{
int num=0;
for(int j=i+1; j<9; j++)
if(s[j]<s[i])num++;
sum+=(num*fac[9-i-1]);
}
return sum+1;
} struct node
{
int matri[10];
int position;
char path[50];
int state;
}; queue<node>que;
char dire[5] = "dlur";
int dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}}; void bfs()
{
memset(vis,false,sizeof(vis));
node cur;
for(int i = 0; i < 8; i++)
cur.matri[i] = i+1;
cur.matri[8] = 0;
cur.state = 46234;
cur.path[0] = '\0';
cur.position = 8;
que.push(cur);
vis[cur.state] = true;
path[cur.state][0] = '\0';
while(!que.empty())
{
cur = que.front();
que.pop();
int x = cur.position/3;
int y = cur.position%3; for(int i = 0; i < 4; i++)
{
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if(tx < 0 || tx > 2 || ty < 0 || ty > 2)
continue;
node t = cur; t.position =tx*3+ty;
t.matri[cur.position] = t.matri[t.position];
t.matri[t.position] = 0;
t.state =cantor(t.matri);
if(!vis[t.state])
{
path[t.state][0] = t.path[0] = dire[i];
int len = strlen(cur.path);
for(int j = 1;j <= len+1;j++)
path[t.state][j] = t.path[j] = cur.path[j-1];
vis[t.state] = true;
que.push(t);
}
}
}
} char ch;
int q[10];
int main()
{
bfs();
while(cin >> ch)
{
if(ch == 'x')
q[0] = 0;
else
q[0] = ch-'0';
for(int i = 1; i < 9; i++)
{
cin >> ch;
if(ch == 'x')
q[i] = 0;
else
q[i] = ch-'0';
}
int ans = cantor(q);
// printf("%d\n",ans);
if(!vis[ans])
printf("unsolvable\n");
else
{
cout <<path[ans]<<endl;
}
}
return 0;
} ②双向bfs + 康拓展开+奇偶剪枝 剪枝:当x左右移动时,序列不变;上下移动时,移动2位后逆序数+2,所以奇偶性不变 双向bfs:因为扩展越大,你要搜索的部分就更多.而同时从开头和结果开始理论上来说会快很多 #include <iostream>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
#include <vector>
typedef long long ll;
using namespace std; const int MAXN=370000;
int fac[]= {1,1,2,6,24,120,720,5040,40320,362880}; //康拖展开判重
// 0!1!2!3! 4! 5! 6! 7! 8! 9!
int vis[MAXN];//标记
int vis2[MAXN];
int cantor(string s)//康拖展开求该序列的hash值
{
int sum=0;
for(int i=0; i<9; i++)
{
int num=0;
for(int j=i+1; j<9; j++)
if(s[j]<s[i])num++;
sum+=(num*fac[9-i-1]);
}
return sum+1;
} struct node
{
string path;
int state;
} From; struct node2
{
int num;
char ch;
} pre[MAXN]; char dire2[5] = "dlur";
char dire1[5] = "urdl";
int dir[4] = {-3,1,3,-1}; void pri(int t)
{
if(pre[t].num == -1)
return ;
pri(pre[t].num);
printf("%c",pre[t].ch);
} void bfs(node cur)
{
queue<node>que1;
queue<node>que2;
memset(vis,0,sizeof(vis));
memset(vis2,0,sizeof(vis2)); pre[0].num = pre[1].num = pre[2].num = -1;
node last,tp;
vis[cantor(cur.path)] = 1;
last.path ="123456780";
last.state = 8;
vis2[cantor(last.path)] = 2;
que1.push(From);
que2.push(last);
int num = 2; while(!que1.empty() && !que2.empty())
{
//正向搜索
cur = que1.front();
que1.pop();
int stat = cantor(cur.path);
if(vis2[stat])
{
pri(vis[stat]);
int k = vis2[stat];
while(pre[k].num != -1)
{
printf("%c",pre[k].ch);
k = pre[k].num;
}
printf("\n");
return;
}
for(int i = 0; i < 4; i++)
{
if(i==0&&cur.state<3)continue; //up
if(i==1&&cur.state%3 == 2)continue; //right
if(i==2&&cur.state>5)continue; //down
if(i==3&&cur.state%3 == 0)continue; //left
int posi = cur.state + dir[i];
tp = cur;
swap(tp.path[cur.state],tp.path[posi]);
int x = cantor(tp.path);
if(vis[x])
continue;
vis[x] = ++num; tp.state = posi;
pre[num].ch = dire1[i];
pre[num].num = vis[stat];
que1.push(tp);
} //反向搜索
last = que2.front();
que2.pop();
stat = cantor(last.path);
if(vis[stat])
{
pri(vis[stat]);
int k =vis2[stat];
while(pre[k].num!=-1)
{
printf("%c",pre[k].ch);
k=pre[k].num;
}
printf("\n");
return ;
}
for(int i = 0; i < 4; i++)
{
if(i==0&&last.state<3)continue;
if(i==1&&last.state%3==2)continue;
if(i==2&&last.state>5)continue;
if(i==3&&last.state%3==0)continue;
int posi = last.state + dir[i];
tp = last;
swap(tp.path[last.state],tp.path[posi]);
int x = cantor(tp.path);
if(vis2[x])
continue;
vis2[x] = ++num; tp.state = posi;
pre[num].ch = dire2[i];
pre[num].num = vis2[stat];
que2.push(tp);
}
}
printf("unsolvable\n");
} bool check(string a)
{
int num = 0;
for(int i = 0; i < 9; i++)
{
if(a[i] == '0' )
continue;
for(int j = i+1; j < 9; j++)
{
if(a[j] == '0') continue;
if(a[j] < a[i])
num++;
}
}
if(num & 1)
return true;
else
return false;
} char ch;
char a[100];
int p[10];
int main()
{
while(gets(a))
{
int tnum = 0;
int n=strlen(a);
From.path="";
for(int i=0; i<n; i++)
if(a[i]!=' ')
{
if(a[i]=='x')
{
From.state=tnum;
From.path+='0';
}
else
From.path+=a[i];
tnum++;
}
if(check(From.path))printf("unsolvable\n");
else
bfs(From);
}
return 0;
} ③A*算法+康拓展开+奇偶剪枝 它把Dijkstra算法(靠近初始点的结点)和BFS算法(靠近目标点的结点)的信息块结合起来。走到终点的代价为f[n],主要由已经花费的代价g[n]和将要花费的代价h[n]决定,f[n] = g[n] + h[n],由于要找最短的路径,优先判定f[n]较小的。 而在本题中g[n]即是已经走过的步数,h[n]则是当前情况移动到-> 123456780的最小步数. #include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <algorithm>
typedef long long ll;
using namespace std; const int MAXN=362880;
int fac[]= {1,1,2,6,24,120,720,5040,40320,362880};
// 0!1!2!3! 4! 5! 6! 7! 8! 9!
int vis[MAXN];
int cantor(int s[])
{
int sum=0;
for(int i=0; i<9; i++)
{
int num=0;
for(int j=0; j<i; j++)
if(s[j]>s[i])num++;
sum+=(num*fac[i]);
}
return sum;
} struct node2
{
int pre;
char ch;
} pre[MAXN]; struct node
{
int matri[10];
int position;
int have,to;
int state;
bool operator < (const node a)const
{
return have+to>a.have+a.to;
}
}; char dire[5] = "urdl";
int dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}}; int fx[]={2,0,0,0,1,1,1,2,2},fy[]={2,0,1,2,0,1,2,0,1};
int get_(node a)
{
int ans = 0;
for(int i = 0; i < 3; i++)
for(int j = 0; j < 3; j++){
if(a.matri[i*3+j]){
ans+=abs(i-fx[a.matri[i*3+j]])+abs(j-fy[a.matri[i*3+j]]);
}
}
return ans;
}
int fina[10]; void pri(int k)
{
if(pre[k].pre == -1) return;
pri(pre[k].pre);
printf("%c",pre[k].ch);
} void bfs(node cur)
{
priority_queue<node>que;
memset(vis,0,sizeof(vis));
vis[cur.state] = 1;
int tnum = 1;
pre[1].pre = -1;
for(int i = 0; i < 8; i++)
fina[i] = i+1;
fina[8] = 0;
int _ans = cantor(fina);
cur.have = 0;
que.push(cur);
while(!que.empty())
{
cur = que.top();
que.pop();
int x = cur.position/3;
int y = cur.position%3;
int num = cur.state;
if(num == _ans)
{
int k = vis[num];
pri(k);
printf("\n");
return ;
}
for(int i = 0; i < 4; i++)
{
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if(tx < 0 || tx > 2 || ty < 0 || ty > 2)
continue;
node t = cur; t.position =tx*3+ty;
t.matri[cur.position] = t.matri[t.position];
t.matri[t.position] = 0;
t.have++;
t.to = get_(t);
t.state =cantor(t.matri);
if(!vis[t.state])
{
vis[t.state] = ++tnum;
pre[tnum].pre = vis[num];
pre[tnum].ch = dire[i];
que.push(t);
}
}
}
printf("unsolvable\n");
} bool check(int a[])
{
int num = 0;
for(int i = 0; i < 9; i++)
{
if(a[i] == 0 )
continue;
for(int j = i+1; j < 9; j++)
{
if(a[j] == 0) continue;
if(a[j] < a[i])
num++;
}
}
if(num & 1)
return true;
else
return false;
} char ch;
int main()
{
while(cin >> ch)
{
node from;
if(ch == 'x')
{
from.matri[0] = 0;
from.position = 0;
}
else
from.matri[0] = ch-'0';
for(int i = 1; i < 9; i++)
{
cin >> ch;
if(ch == 'x')
{
from.matri[i] = 0;
from.position = i;
}
else
from.matri[i] = ch-'0';
}
int ans = cantor(from.matri);
from.state = ans;
// printf("%d\n",ans);
if(check(from.matri))
printf("unsolvable\n");
else
bfs(from);
}
return 0;
}
hdu 1043(经典搜索)的更多相关文章
- HDU 1043 Eight 八数码问题 A*算法(经典问题)
HDU 1043 Eight 八数码问题(经典问题) 题意 经典问题,就不再进行解释了. 这里主要是给你一个状态,然后要你求其到达\(1,2,3,4,5,6,7,8,x\)的转移路径. 解题思路 这里 ...
- HDU - 1043 - Eight / POJ - 1077 - Eight
先上题目: Eight Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tota ...
- POJ-1077 HDU 1043 HDU 3567 Eight (BFS预处理+康拓展开)
思路: 这三个题是一个比一个令人纠结呀. POJ-1077 爆搜可以过,94ms,注意不能用map就是了. #include<iostream> #include<stack> ...
- HDU 1043 Eight(八数码)
HDU 1043 Eight(八数码) 00 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Problem Descr ...
- Eight POJ - 1077 HDU - 1043 八数码
Eight POJ - 1077 HDU - 1043 八数码问题.用hash(康托展开)判重 bfs(TLE) #include<cstdio> #include<iostream ...
- (中等) HDU 1043 Eight,经典搜索问题。
Problem Description The 15-puzzle has been around for over 100 years; even if you don't know it by t ...
- hdu 1043 Eight 经典八数码问题
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 The 15-puzzle has been around for over 100 years ...
- HDU 1043 Eight 【经典八数码输出路径/BFS/A*/康托展开】
本题有写法好几个写法,但主要思路是BFS: No.1 采用双向宽搜,分别从起始态和结束态进行宽搜,暴力判重.如果只进行单向会超时. No.2 采用hash进行判重,宽搜采用单向就可以AC. No.3 ...
- HDU 1043 八数码(A*搜索)
在学习八数码A*搜索问题的时候须要知道下面几个点: Hash:利用康托展开进行hash 康托展开主要就是依据一个序列求这个序列是第几大的序列. A*搜索:这里的启示函数就用两点之间的曼哈顿距离进行计算 ...
随机推荐
- python之路--day11---迭代器和生成器
迭代: 迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的初始值 为什么要有迭代器: 数据类型的取值,字符串,列表,元组依靠索引可以取值,但是字典,集合,文件这些数据类型无法 ...
- python 判断变量是否是 None 的三种写法
代码中经常会有变量是否为None的判断,有三种主要的写法:第一种是`if x is None`:第二种是 `if not x:`:第三种是`if not x is None`(这句这样理解更清晰`if ...
- Docker学习笔记 - Docker数据卷的备份和还原
学习目标: 备份数据卷 还原数据卷 # 通过容器备份数据卷容器中的数据卷 docker run --volumes-from dvt5 -v ~/backup:/backup --name dvt10 ...
- 理解JavaScript中函数方法
1.函数声明和函数表达式 通过字面量创建函数的方式有两种函数声明和函数表达式: 函数声明: function sum(x, y) { var result = x + y; return result ...
- POJ1236【Tarjan+缩点】
题目大意:有向关系体现在电脑可以通过网络单向的传输文件,并规定一旦有电脑存在该文件,那么所有它能传输的电脑就能在第一时间得到这个文件,题目有两个问题,第一个是最少向网络中的几台电脑投放文件,能使得整个 ...
- Struts(十二):异常处理:exception-mapping元素
配置当前action的声明异常处理 1.exception-mapping元素中有2个属性 exception:指定需要捕获的异常类型 result:指定一个响应结果,该结果将在捕获到异常时被执行.即 ...
- QT生成随机数
QT生成随机数和C语言差距不大,C语言用srand()和rand(),QT是用Qsrand()和qrand(): QT生成随机数的格式是: qsrand(QTime(0,0,0).secsTo(QTi ...
- hdu1022 Train Problem I---模拟栈
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1022 题目大意: 车的进出站问题,先给出N个火车,再按序列一的方式进站,判断能否以序列二的方式出站,若 ...
- in成员资格符
#in成员资格符 name='小树' '小'in name# 返回True '大树'in name#返回False
- springCloud 微服务框架搭建入门(很简单的一个案例不喜勿扰)
Spring cloud 实现服务注册及发现 服务注册与发现对于微服务系统来说非常重要.有了服务发现与注册,你就不需要整天改服务调用的配置文件了,你只需要使用服务的标识符,就可以访问到服务. clou ...