题意:一个n*n格的棋盘,从1标号到n*n。从1开始走,每次投色子,可走1到6步中的任意一个步数,问最少投几次色子可到最后一格。其中有两种特殊通道,蛇和梯子,在蛇头所在的格子可以直接走到蛇尾所在的格子,在梯子底端所在的格子可以直接走到梯子顶端所在的格子。

思路:由于蛇和梯子作用是一样的,所以可以把它们看成一种。又由于蛇和梯子是不会重合的,所以它们不可能在同一个位置出现。故可以用bar[x]数组来保存在特殊位置x处可以到达的位置y。棋盘用mp数组表示,1表示能到达,0表示不能到达。

 

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<queue>
using namespace std;
const int N=23;
struct node
{
    int from,to;
};
int main()
{
    int t,n,s,l;
    int mp[N*N],mp1[N*N];//棋盘
    node bar[250];//梯子和蛇
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&s,&l);
        for(int i=1;i<=s+l;i++)
        {
            scanf("%d%d",&bar[i].from,&bar[i].to);
        }
        memset(mp,0,sizeof(mp));
        mp[1]=1;//从第一格开始,初始化为1;
        int step=0,deal;//step初始化筛子次数
        while(mp[n*n]==0)//终点为1即为到达终点
        {
            memcpy(mp1,mp,sizeof(mp));//mp1【】备份上一步的棋盘状态
            memset(mp,0,sizeof(mp));//mp【】保存上一步棋盘状态下进行拓展后的状态
            for(int j=1;j<=n*n-1;j++)
            {
                if(mp1[j]==0) continue;//上一步无法到达此格,则跳过
                for(int i=1;i<=6;i++)//筛子点数1到6,走后到达j+i位置;
                {
                    deal=0;
                    if(j+i>n*n) break;//超出棋盘,break;
                    for(int k=1;k<=s+l;k++)
                    {
                        if(bar[k].from==j+i)//如果j+i位置是蛇或是梯子,到达他的to位置
                        {
                            mp[bar[k].to]=1;
                            deal=1;break;
                        }
                    }
                    if(!deal&&!mp[j+i]) mp[j+i]=1;//不利用蛇或者梯子
                }
            }
            step++;//摇骰子次数加一
        }
        printf("%d\n",step);
    }
    return 0;

}
/*
2
6 1 3
35 25
3 23 5 16 20 33
*/