有一个8X8的棋盘,上面有4个棋子,棋子可以上下左右移动。给定一个初始状态和一个目标状态,问能否在8步之内到达。
#include<iostream>
using namespace std;
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
const int vex[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};//方向向量
char vis[8][8][8][8][8][8][8][8];
struct Chess//棋子
{int x, y;
};
struct Node//状态
{Chess ches[4];int step;
};
class cmp//谓词类:小于//装了个X,可以直接写cmp函数的
{
public:bool operator()(Chess c1, Chess c2){if(c1.x == c2.x)return c1.y < c2.y;elsereturn c1.x < c2.x;}
};
void sortNode(Node& node)//排序数据之后才是状态
{sort(node.ches, node.ches+4, cmp());//cmp()是一个匿名类!
}
bool movee(Node& next, int c, int v)//chess[c]向vex[v]移动一步
{next.ches[c].x += vex[v][0];next.ches[c].y += vex[v][1];if(next.ches[c].x < 1 || next.ches[c].x > 8 || next.ches[c].y < 1 || next.ches[c].y > 8){return false;//棋盘越界}for(int i = 0; i < 4; i++){if(i != c && next.ches[c].x == next.ches[i].x && next.ches[c].y == next.ches[i].y){return false;//重叠}}return true;
}
bool tGetNode(Node& next, Node& src, int c, int v)//根据参数尝试获取一个状态,成功返回true
{for(int i = 0; i < 4; i++){next.ches[i] = src.ches[i];}next.step = src.step + 1;//棋子移动,当不成功是可以在移动一步for(int i = 0; i < 2; i++){if(movee(next, c, v)){//成功sortNode(next);return true;}}return false;//移动失败
}
char& atVis(Chess ches[])//根据状态返回vis相应一个位置引用:不用每次都写8维数组。注意减去1
{return vis[ches[0].x-1][ches[0].y-1][ches[1].x-1][ches[1].y-1][ches[2].x-1][ches[2].y-1][ches[3].x-1][ches[3].y-1];
}
//保存开始状态,目标状态
Node beg, tar;//从start状态进行广搜,已经搜索的标记sign,遇到endsign就成功,返回true
bool bfs(Node& start, char sign, char endsign)
{Node node, next;queue<Node> q;q.push(start);atVis(start.ches) = sign;//标记while(!q.empty()){node = q.front();q.pop();if(node.step < 4){//还没到4步for(int c = 0; c < 4; c++)//棋子维度for(int v = 0; v < 4; v++){//方向维度if(tGetNode(next, node, c, v)){//存在该转移方法的一个状态if(atVis(next.ches) == 0){//未被搜索过atVis(next.ches) = sign;//标记q.push(next);}else if(atVis(next.ches) == endsign){//找到结束标志return true;}}}}}return false;
}int main()
{//freopen(", "r", stdin);while(~scanf("%d%d", &beg.ches[0].x, &beg.ches[0].y)){//每一个案例for(int i = 1; i < 4; i++)scanf("%d%d", &beg.ches[i].x, &beg.ches[i].y);sortNode(beg);beg.step = 0;for(int i = 0; i < 4; i++)scanf("%d%d", &tar.ches[i].x, &tar.ches[i].y);sortNode(tar);tar.step = 0;memset(vis, 0, sizeof(vis));//第一个bfs搜索后标记‘2’,作为第二个bfs的搜索目标(本质)//第一个bfs返回false(因为没有‘1’)if(bfs(tar,'2', '1') || bfs(beg, '1', '2'))printf("YESn");//第二个bfs返回了trueelseprintf("NOn");//第二个bfs返回了false}return 0;
}
在一个二维空间上,有一个点,可以上下左右四个方向可以移动一步。给出一个初始点和一个终点,问在在n步之内能否到达。
对于这题,非常简单,一个状态只由一个 点决定(hdu1401是4个点)。vis*是一个2维数组。
注意到,一个点1x2维,四个点4x2=8维,所以!!!hdu1401在某种意义下可以看作给定两个点(两种状态),问在8维空间中 8步之内初始状态(初始点)能否到达给定终点状态?
而且,因为空间中没有障碍,可以根据曼哈顿距离直接使用贪心法!!不用暴力的bfs,岂不美滋滋??!
事实上这是错的:
关于A*算法(bfs+贪心),应该使用的是优先队列priority_queue.
//伪代码
bfsA(状态 star, 状态 tar, 标记 sign, 搜索目标标记 tarsign){q.push(star);atVis(star) = sign;while(!q.empty()){node = q.top();q.pop();for(遍历步长临近的点){if(tryGetNext(next, node)){//tryGetNext:尝试获取下一个状态,评估函数最优是优先级最高if 搜索成功 atVis(next) == tarsign退出,返回结果elseq.push(next); atVis(next) = sign;}}}
}
本文发布于:2024-01-29 07:58:51,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170648633613836.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |