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;
}

 

posted on 2012-09-02 22:19  pcoda  阅读(1000)  评论(0编辑  收藏  举报