Uva 816. Abbott的复仇(BFS求最短路)
//完全参考刘汝佳算法竞赛入门经典
首先来看看题,从不同方向(北东南西NESW)进入不同节点后,它可以做的操作(直行F,左拐L,右拐R)是不同的。
设每次移动是从 出发点 ---》 目标点
const char* dirs = "NESW";//设立北0东1南2西3
const char* turns = "FLR";//这块结合后面操作。如果直行的话,出发点的dir和目标点一样;如果左转的话,目标点的dir 比 出发点的dir小1;右转的话则大1。
int dir_id(char c){
return strchr(dirs,c) - dirs;
} //获得字符c的位置(是第几个——int数据)
int turn_id(char c){
return strchr(turns,c) - turns;
}
接下来进行 “行走”函数
int dx[] = {-1,0,1,0};
int dy[] = {0,1,0,-1};
Node walk(const Node& u,int turn){//注意,Node结构体已经包含了来自的方向,所以不需要再加 方向
if(turn = 0)int dir = u.dir;
if(turn = 1)int dir = (u.dir + 3)%4;//本来应该是-1,但是负数无法取模,所以顺时针转3个单位==逆时针转1个单位。
if(turn = 2)int dir = (u.dir + 1)%4
return Node(u.r + dx[dir],u.c+dy[dir])
}//如果 目标点.dir =N北,那么出发点肯定在目标点的北方,所以“目标点.y = 出发点.y - 1",同理其他方位也可以得出来相应的差。
接下来搞输入部分,分析一下输入的数据
SAMPLE //先读入一个示例名字
3 1 N 3 3 //再读入起始点
1 1 WL NR * //各个节点不同方向允许的操作,以*结尾
1 2 WLF NR ER *
1 3 NL ER *
2 1 SL WR NF *
2 2 SL WF ELF *
2 3 SFR EL *
0 //以0代表所有节点输入完毕
NOSOLUTION
3 1 N 3 2
1 1 WL NR *
1 2 NL ER *
2 1 SL WR NFR *
2 2 SR EL *
0
END //以END作为示例名称标志着程序程序整体结束。
把数据都读入
bool input(){
memset(has_edge, 0, sizeof(has_edge));
cin >> name;//示例名字
if(name == "END") return false;
char s[100];
cin >> r0 >> c0 >> s >> r2 >> c2;//输入起始和目标位置
cout << name << endl;//直接先输出名字
r1 = r0 + dy[dir_id(s[0])];
c1 = c0 + dx[dir_id(s[0])];
dir = dir_id(s[0]);
int r, c;
while(cin >> r){
if(r == 0) break;
cin >> c;
char s2[100];
while(cin >> s2){//循环读入一个节点某个方向的可以转的方向
if(s2[0] == '*') break;//当输入*时,此节点结束
int l = strlen(s2);
for(int i = 1; i < l; ++i){
has_edge[r][c][dir_id(s2[0])][turn_id(s2[i])] = 1;
}
}
}
return true;//全都输入完毕,返回true,然后继续下一次示例
}
再来一发BFS主体:
void solve(){
queue<Node> q;
memset(d, -1, sizeof(d));
Node u(r1, c1, dir);
d[u.r][r.c][u.dir] = 0;
q.push(u);
while(!q.empty()){
Node u = q.front();
q.pop();
if(u.r == r2 && u.c == c2) {//达到目的地时的状态:q有1个——q进行判断,是目标节点——输出,并返回,
print_ans(u);
return;
}
for(int i = 0; i < 3; ++i){
Node v = walk(u,i);
if(has_edge[u.r][u.c][u.dir][i]&&inside(v.r,v.c)&&d[v.r][v.c][v.dir] < 0){
d[v.r][v.c][v.dir] = d[u.r][u.c][u.dir] + 1;//如果满足上面条件(未被探索),那么就标记其为探索过
p[v.r][v.c][v.dir] = u;
q.push(v);
}
}
}
printf("No Solution Possible
");//如果有答案的话,每一步的状态都保证q非空(包括目标和起始位置那一步)
}
再把解的路线输出出来。
void print_ans(Node u){
vector<Node> nodes;
for(;;){
nodes.push_back(u);
if(d[u.r][u.c][u.dir] == 0) break;//回溯到了起点
u = p[u.r][u.c][u.dir];
}
nodes.push_back(Node(r0,c0,dir));
int cnt = 0;
for(int i = nodes.size()-1;i >= 0; i--){
if(cnt % 10 == 0) printf(" ");
printf(" (%d,%d)",nodes[i].r,nodes[i].c);
if(++cnt %10 == 0) printf("
");
}
if(nodes.size()%10 != 0) printf("
");
}
好了,写完了。
其中输入处理的时候,不小心把s2写成了s,c写成了r,导致了错误,改回来了
但是vj上一直WA,去debug找了一下这道题的数据点,和我的对比了一下,也是一样的。不知道是哪里出了问题。