题意:给出一个完全图,任意两点间都有边,每条边都有一个颜色,在某3个点上各放了1个棋子,每次只允许让一个棋子通过一条边走到另一个点上并且走的这条边的颜色必须和另外两个棋子之间的边颜色相同(完全图,任意两点都有边),求走到同一个点上最少步数.
思路:可以设计一个3维的状态,dis[x][y][z]代表3个点分别在x, y, z点上时候的最少步数,那么就可以用类似spfa的松弛方法来更新就可以了.
注意刚开始3个点可能已经在同一个点上了.
#include <cstdio>
#include <queue>
#include <memory.h>
using namespace std;
const int MAX = 51;
int dis[MAX][MAX][MAX];
int g[MAX][MAX];
int n;
int s1, s2, s3;
struct Node{
int x, y, z, step;
Node(int x_ = 0, int y_ = 0, int z_ = 0, int step_ = 0):x(x_), y(y_), z(z_), step(step_){}
};
int spfa(){
memset(dis, 0x20, sizeof(dis));
dis[s1][s2][s3] = 0;
int ans = 0x20202020;
queue<Node> q;
q.push(Node(s1, s2, s3, 0));
while(!q.empty()){
Node f = q.front();
q.pop();
int x = f.x, y = f.y, z = f.z;
for(int i = 1; i <= n; ++i){
if(i != x && g[x][i] == g[y][z]){
if(dis[i][y][z] > f.step + 1){
dis[i][y][z] = f.step + 1;
q.push(Node(i, y, z, f.step + 1));
}
}
}
for(int i = 1; i <= n; ++i){
if(i != y && g[y][i] == g[x][z]){
if(dis[x][i][z] > f.step + 1){
dis[x][i][z] = f.step + 1;
q.push(Node(x, i, z, f.step + 1));
}
}
}
for(int i = 1; i <= n; ++i){
if(i != z && g[z][i] == g[x][y]){
if(dis[x][y][i] > f.step + 1){
dis[x][y][i] = f.step + 1;
q.push(Node(x, y, i, f.step + 1));
}
}
}
}
for(int i = 1; i <= n; ++i){
if(dis[i][i][i] < ans){
ans = dis[i][i][i];
}
}
return ans;
}
int main(int argc, char const *argv[]){
while(scanf("%d", &n) == 1){
if(!n)break;
scanf("%d%d%d", &s1, &s2, &s3);
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j){
char c[2];
scanf("%s", c);
g[i][j] = c[0];
}
}
if(s1 == s2 && s1 == s3){
printf("0\n");
continue;
}
int ans = spfa();
if(ans == 0x20202020){
printf("impossible\n");
}else{
printf("%d\n", ans);
}
}
return 0;
}