三、棋盘 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; }
此方法为记忆化搜索,用广度优先搜索是最好的解决方案。