http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1103
题目大意:
“Hike on a Graph”是一种在木板上玩的游戏,木板上有衣服无向图。图是完整的并画有所有回路,即任意两个位置之间都有一条标线,标线有各种不同的颜色。有三个游戏者,他们各有一个棋子。游戏开始时,这三个棋子放在涂上的固定位置。游戏者需要按照顺序移动棋子,每次移动只要沿着板上无向图的标线从现在的位置搬到新位置。限制如下:当标线的颜色与两个一直之间的标线颜色一样时,棋子才能移动。
在20实际60年代,有一款单人玩的游戏,在这款游戏里,一个人要移动三个棋子,不必一个接着一个移动,但每次只能移动一个棋子,游戏的任务是:用最少的步数,将所有的棋子移动到同一个位置上。根据木板上图的布局及棋子的开始位置,计算出最少步数,把所有的棋子移动到同一个位置上。
输入格式:
输入有多组数据。对每组数据,第一个数据是n(1=<n<=50)。当n=0时输入结束。然后是三个整数p1,p2,p3(1=<pi<=n),表示棋子的初始位置。标线颜色由矩阵n*n表示,都是小写字母(字母之间用空格隔开)。矩阵元素mij表示位置i和j之间的标线颜色。因为游戏图是无向的,你可以认为矩阵是对称的。
输出格式:
对每组数据,输出一行:是把所有的 棋子都移动到同一个位置上,所需要的最少步数。如果无法实现目标,只需输出“impossible”。
算法分析:
给定一个无向图,每条边都有一个颜色。游戏开始时,有三个棋子在图的三个结点上。每次可以沿着一条边移动任意一个棋子,要求改变的颜色和另外两个棋子之间边的颜色相同。要求用最少的步数,将所有的棋子移动到同一个位置。
采用广度优先算法,判定目标能否实现,以及计算实现目标所需要的最少步骤。
对于第一组数据,各个结点之间边的颜色如图所示:
结点 |
1 |
2 |
3 |
1 |
r |
b |
r |
2 |
b |
b |
b |
3 |
r |
b |
r |
从图中看出,结点本身存在自循环,是有边的。如结点1,自循环边的颜色是r。
结点2、3上有棋子,结点之间的颜色是b,可以把结点1上的棋子移动到结点2(边的颜色是b);结点2自循环的颜色是b,可以把结点3上的棋子移动到结点2(边的颜色是b)。这样2步就可以把棋子都移动到结点2上面了。
对于第二组数据,结点自循环的颜色与相邻结点之间边的颜色不一样,棋子无法移动,所以是“impossible”。
(2)数据结构
对于三个棋子到达不同位置所需要的步数,用数组ans[51][51][51];
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; int n,ok,p1,p2,p3; int ans[51][51][51]; char map[51][51]; struct Hike{ char a,b,c; }; void bfs() { int i,a,b,c; queue<Hike>Q; Hike tmp; ans[p1][p2][p3] = 0; tmp.a = p1; tmp.b = p2; tmp.c = p3; Q.push(tmp); while(!Q.empty()) { tmp = Q.front(); Q.pop(); a = tmp.a; b = tmp.b; c = tmp.c; if((a == b) && (a == c)) //到达同一个位置,结束 { ok = a; break; } int current = ans[a][b][c]; //当前结点的步数值 current ++; char *color ; char bcColor = map[b][c]; //结点b、c的颜色 color = map[a]+1; for(i=1;i<=n;i++,color++) { //如果不是结点a,并且改边与bc之间的边颜色相同 //存储的步数币当前所需要的步数大 if(i != a && *color == bcColor && ans[i][b][c] > current) { ans[i][b][c] = current; tmp.a = i; tmp.b = b; tmp.c = c; Q.push(tmp); } } char acColor = map[a][c]; //结点a、c之间的颜色 color = map[b] + 1; for(i=1;i<=n;i++,color++) { if(i != b && *color == acColor && ans[a][i][c] > current) { ans[a][i][c] = current; tmp.a = a; tmp.b = i; tmp.c = c; Q.push(tmp); } } char abColor = map[a][b]; //结点a、b之间的颜色 color = map[c] + 1; for(i=1;i<=n;i++,color++) { if(i != c && *color == abColor && ans[a][b][i] > current) { ans[a][b][i] = current; tmp.a = a; tmp.b = b; tmp.c = i; Q.push(tmp); } } } } int main() { int i,j; char str[110]; while(scanf("%d",&n)!=EOF && n) { scanf("%d%d%d\n",&p1,&p2,&p3); for(i=1;i<=n;i++) { gets(str); for(j=0;j<n;j++) sscanf(str+2*j,"%c",&map[i][j+1]); map[i][n+1] = '\0'; } ok = 0; fill(&ans[0][0][0],&ans[0][0][0]+51*51*51,255); bfs(); if(ok) printf("%d\n",ans[ok][ok][ok]); else printf("impossible\n"); } return 0; }