NOIP2017普通组复赛题解三

三、棋盘 chess

【题目描述】

有一个m×m的棋盘,棋盘上每一个格子可能是红色、黄色或没有任何颜色的。你现在要从棋盘的最左上角走到棋盘的最右下角。

任何一个时刻,你所站在的位置必须是有颜色的(不能是无色的),你只能向上、 下、左、 右四个方向前进。当你从一个格子走向另一个格子时,如果两个格子的颜色相同,那你不需要花费金币;如果不同,则你需要花费1个金币。

另外,你可以花费2个金币施展魔法让下一个无色格子暂时变为你指定的颜色。但这个魔法不能连续使用, 而且这个魔法的持续时间很短,也就是说,如果你使用了这个魔法,走到了这个暂时有颜色的格子上,你就不能继续使用魔法;只有当你离开这个位置,走到一个本来就有颜色的格子上的时候,你才能继续使用这个魔法,而当你离开了这个位置(施展魔法使得变为有颜色的格子)时,这个格子恢复为无色。

现在你要从棋盘的最左上角,走到棋盘的最右下角,求花费的最少金币是多少?

【输入格式】

第一行包含两个正整数m、n,以一个空格分开,分别代表棋盘的大小,棋盘上有颜色的格子的数量。

接下来的n行,每行三个正整数x、y、c,分别表示坐标为(x,y)的格子有颜色c。

其中c=1代表黄色,c=0 代表红色。相邻两个数之间用一个空格隔开。棋盘左上角的坐标为(1,1),右下角的坐标为(m,m)。

棋盘上其余的格子都是无色。保证棋盘的左上角,也就是(1,1) 一定是有颜色的。

【输出格式】

一个整数,表示花费的金币的最小值,如果无法到达,输出−1。

【输入样例一】

5 7
1 1 0
1 2 0
2 2 1
3 3 1
3 4 0
4 4 1
5 5 0

【输出样例一】

8

【输入样例二】

5 5
1 1 0
1 2 0
2 2 1
3 3 1
5 5 0

【输出样例二】

-1

【数据规模与约定】
对于30%的数据,1≤m≤5,1≤n≤10。

对于60%的数据, 1≤m≤20,1≤n≤200。

对于100%的数据, 1≤m≤100,1≤n≤1,000。

【解析】

#include<bits/stdc++.h>
using namespace std;
int minn[110][110][2];
int n,m,ans=10000;
int a[110][110];
void DFS (int x,int y,int cos,bool way,int c)
{
    if (minn[x][y][c]<=cos)
        return;
    minn[x][y][c]=cos;
    if (x==m&&y==m)
    {
        ans=min (ans,cos);
        return;
    }
    if (c==a[x+1][y])
        DFS (x+1,y,cos,1,c);
    else if (a[x+1][y]!=-1)
        DFS (x+1,y,cos+1,1,a[x+1][y]);
    else if (way)
    {
        if (c==1)
        {
            DFS (x+1,y,cos+2,0,1);
            DFS (x+1,y,cos+3,0,0);
        }
        else
        {
            DFS (x+1,y,cos+2,0,0);
            DFS (x+1,y,cos+3,0,1);
        }
    }

    if (c==a[x-1][y])
        DFS (x-1,y,cos,1,c);
    else if (a[x-1][y]!=-1)
        DFS (x-1,y,cos+1,1,a[x-1][y]);
    else if (way)
    {
        if (c==1)
        {
            DFS (x-1,y,cos+2,0,1);
            DFS (x-1,y,cos+3,0,0);
        }
        else
        {
            DFS (x-1,y,cos+2,0,0);
            DFS (x-1,y,cos+3,0,1);
        }
    }

    if (c==a[x][y+1])
        DFS (x,y+1,cos,1,c);
    else if (a[x][y+1]!=-1)
        DFS (x,y+1,cos+1,1,a[x][y+1]);
    else if (way)
    {
        if (c==1)
        {
            DFS (x,y+1,cos+2,0,1);
            DFS (x,y+1,cos+3,0,0);
        }
        else
        {
            DFS (x,y+1,cos+2,0,0);
            DFS (x,y+1,cos+3,0,1);
        }
    }
    if (c==a[x][y-1])
        DFS (x,y-1,cos,1,c);
    else if (a[x][y-1]!=-1)
        DFS (x,y-1,cos+1,1,a[x][y-1]);
    else if (way)
    {
        if (c==1)
        {
            DFS (x,y-1,cos+2,0,1);
            DFS (x,y-1,cos+3,0,0);
        }
        else
        {
            DFS (x,y-1,cos+2,0,0);
            DFS (x,y-1,cos+3,0,1);
        }
    }
}
int main()
{
    freopen ("chess.in","r",stdin);
    freopen ("chess.out","w",stdout);
    memset (minn,-1,sizeof (minn));
    memset (a,-1,sizeof (a));
    scanf ("%d%d",&m,&n);
    for (int i=1;i<=n;i++)
    {
        int x,y,c;
        scanf ("%d%d%d",&x,&y,&c);
        a[x][y]=c;
    }
    for (int i=1;i<=m;i++)
        for (int j=1;j<=m;j++)
        {
            minn[i][j][0]=10000;
            minn[i][j][1]=10000;
        }
    DFS (1,1,0,1,a[1][1]);
    if (ans==10000)
    {
        printf ("-1");
        return 0;
    }
    printf ("%d",ans);
    return 0;
}

此方法为记忆化搜索,用广度优先搜索是最好的解决方案。

猜你喜欢

转载自www.cnblogs.com/ziyuwang/p/10425877.html