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*搜索:这里的启示函数就用两点之间的曼哈顿距离进行计算 ...
随机推荐
- DML数据操作语言之查询(二)
当我们查询出了N条记录之后 ,我们知道一共是几条记录,或者这些记录某一字段(列值)的最大值,最小值,平均值等,就可以使用聚合函数. 1.聚合函数 聚合函数会将null 排除在外.但是count(*)例 ...
- JAVAEE——BOS物流项目09:业务受理需求分析、创建表、实现自动分单、数据表格编辑功能使用方法和工作单快速录入
1 学习计划 1.业务受理需求分析 n 业务通知单 n 工单 n 工作单 2.创建业务受理环节的数据表 n 业务通知单 n 工单 n 工作单 3.实现业务受理自动分单 n 在CRM服务端扩展方法根据手 ...
- 静态链表的C实现(基于数据结构 严蔚敏)
静态链表是利用一维数组实现逻辑上的单链表结构,结点的逻辑上相邻但物理位置上不一定相邻,因为内存分配上是一次性的,故称为静态. 特点: 预先需要一片连续的存储空间: 非随机存取: 无现成的"内 ...
- C# 启动 SQL Server 服务
//首先要添加 System.ServiceProcess.dll 引用 ServiceController sc = new ServiceController("MSSQLSERVER& ...
- 获取apk项目的MD5值和SHA1值
一些可说可不说的话: * 以前有一个更简单的方法,在as的右边工具栏的 gradle 面板中可以很方便的获取到: * 上次用也是在2年前,时间长了给忘记了,不过我记得我当时写了笔记,这会笔记不在身边, ...
- redis命令详解
redis中添加key value元素:set key value; 获取元素:get key ; redis中添加集合:lpush key value1 value2 value ...
- Docker1.12.6+CentOS7.3 的安装
安装旧版的docker-engine-1.12.6 kubeadm init --api-advertise-addresses=172.16.160.211命令的时候,提示docker版本太新了 一 ...
- python实现归并排序,归并排序的详细分析。
学习归并排序的过程是十分痛苦的.它并不常用,看起来时间复杂度好像是几种排序中最低的,比快排的时间复杂度还要低,但是它的执行速度不是最快的.很多朋友不理解时间复杂度低为什么运行速度不一定快,这个不清楚的 ...
- Mybatis多个参数传值方法
第一种方案 DAO层的函数方法 Public User selectUser(String name,String area); 对应的Mapper.xml <select id="s ...
- 解决Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/Student_recruit]]
查看web.xml文件的书写,特别注意路径与命名一致