ZOJ-1103-Hike on a Graph

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;

}

 

你可能感兴趣的:(Graph)