【题目描述】 原题目 链接地址:
有一个m × m的棋盘,棋盘上每一个格子可能是红色、黄色或没有任何颜色的。你现在要从棋盘的最左上角走到棋盘的最右下角。
任何一个时刻,你所站在的位置必须是有颜色的(不能是无色的),你只能向上、下、左、右四个方向前进。当你从一个格子走向另一个格子时,如果两个格子的颜色相同,那你不需要花费金币;如果不同,则你需要花费 1 个金币。
另外,你可以花费 2 个金币施展魔法让下一个无色格子暂时变为你指定的颜色。但这个魔法不能连续使用,而且这个魔法的持续时间很短,也就是说,如果你使用了这个魔法,走到了这个暂时有颜色的格子上,你就不能继续使用魔法;只有当你离开这个位置,走到一个本来就有颜色的格子上的时候,你才能继续使用这个魔法,而当你离开了这个位置(施展魔法使得变为有颜色的格子)时,这个格子恢复为无色。
现在你要从棋盘的最左上角,走到棋盘的最右下角,求花费的最少金币是多少?
【输入格式】
数据的第一行包含两个正整数 m,n,以一个空格分开,分别代表棋盘的大小,棋盘上 有颜色的格子的数量。
接下来的 n 行,每行三个正整数 x,y,c,分别表示坐标为(x,y)的格子有颜色 c。其中 c=1 代表黄色,c=0 代表红色。 相邻两个数之间用一个空格隔开。 棋盘左上角的坐标为(1, 1),右下角的坐标为(m, m)。
棋盘上其余的格子都是无色。保证棋盘的左上角,也就是(1,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
【样例输出1】
8
图片省略~~
-------------------------------------------------------------------------------
分析:记忆化搜索, 用DP[i][j]表示走到(i,j)时的最小代价,如果当前深搜到的代价sum>=dp[i][j],直接return ; 否则更新dp[i][j]——表示这是一个更优的解,然后继续递归!与sum的判断,每一个if条件都不能省!
/* 同种颜色可以直接跳上去;/0红色,1黄色,-1空格
跳到不同颜色花费1金币;
op=1, 或者跳到空格-1上,开销为2,然后 再跳到有色的地方--开销1或者0;*/
-----------------------------------------------------------------------------------
AC题解:


int m,n; //和题意描述的相反,m表示有颜色的点数,n表示正方形的边长 int G[N][N];//存贮每个格点的颜色情况! int ans; int dir[4][2]={ {-1,0},{1,0},{0,-1},{0,1} }; int dp[N][N];//用DP[i][j]表示走到(i,j)时的最小代价 void dfs(int x,int y,int sum,int op,int col){ // printf("**(%d,%d) sum=%d op=%d col=%d\n",x,y,sum,op,col); if(x==n&&y==n){ ans=min(ans,sum); // printf("________sum=%d\n",sum); return ; } for(int i=0;i<4;i++){ int dx=x+dir[i][0]; int dy=y+dir[i][1]; if(dx<1||dy<1||dx>n||dy>n) continue; if(sum>=dp[dx][dy])//进行优化,dp[][]记忆之前达到该点的最小花费! continue ; if(G[dx][dy]>=0){ if(col==G[dx][dy]){//代价为零,同种颜色! dp[dx][dy]=sum; dfs(dx,dy,sum,0,col); } else{ //代价为1,异种颜色,可以非一次! dp[dx][dy]=sum+1; dfs(dx,dy,sum+1,0,!col); } } else{ if(op==0&&dp[dx][dy]>sum+2 ){ //上面有条件:dp[dx][dy]>sum dp[dx][dy]=sum+2; dfs(dx,dy,sum+2,1,col);//op改为1表示跳到空格上了,下一步要小心! } } } } int main(){ // freopen("checkerboard.in","r",stdin); // freopen("checkerboard.out","w",stdout); int x,y,z; scanf("%d%d",&n,&m); memset(G,-1,sizeof(G)); for(int i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&z); G[x][y]=z;//0红色,1黄色 } memset(vis,0,sizeof(vis)); ans=inf; memset(dp,inf,sizeof(dp)); dp[0][0]=0; dfs(1,1,0,0,G[1][1]);//省时需要记忆化搜索!! if(ans==inf){ printf("-1\n"); } else{ printf("%d\n",ans); } return 0; }