【题解】luogu P3956 棋盘

luogu P3956 棋盘

题目描述

有一个m×m的棋盘,棋盘上每一个格子可能是红色、黄色或没有任何颜色的。你现在要从棋盘的最左上角走到棋盘的最右下角。
任何一个时刻,你所站在的位置必须是有颜色的(不能是无色的), 你只能向上、 下、左、 右四个方向前进。当你从一个格子走向另一个格子时,如果两个格子的颜色相同,那你不需要花费金币;如果不同,则你需要花费 1个金币。
另外, 你可以花费 2 个金币施展魔法让下一个无色格子暂时变为你指定的颜色。但这个魔法不能连续使用, 而且这个魔法的持续时间很短,也就是说,如果你使用了这个魔法,走到了这个暂时有颜色的格子上,你就不能继续使用魔法; 只有当你离开这个位置,走到一个本来就有颜色的格子上的时候,你才能继续使用这个魔法,而当你离开了这个位置(施展魔法使得变为有颜色的格子)时,这个格子恢复为无色。
现在你要从棋盘的最左上角,走到棋盘的最右下角,求花费的最少金币是多少?

输入输出格式
输入格式:

第一行包含两个正整数 m, n,以一个空格分开,分别代表棋盘的大小,棋盘上有颜色的格子的数量。
接下来的 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

输入样例#2:

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

输出样例#2:

-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;
const int maxn=2000+10,INF=2147483646;
int ans,dx[4]={-1,0,1,0},dy[4]={0,-1,0,1}/*四个方位*/,f[maxn][maxn]/*存储图表*/,a[maxn][maxn]/*用于剪枝*/,n,m,x,y,c;
void dfs(int x,int y/*x,y坐标*/,int sum/*当前的总钱数*/,bool magic/*是否用了魔法(~~膜法~~)*/){
	if(x>m||y>m||x<1||y<1)//超界就直接返回
		return;
	if(sum>=a[x][y])//重点剪枝!!!如果以前的最优还比当前的走法更优,就不用找了,毫无意义。
		return;
	a[x][y]=sum;//将a[x][y]替换为当前的最大sum值
	if(x==m&&y==m){//如果到达了最后一格
		ans=min(ans,sum);//那么就判断到达最后一格所用的钱数sum是否小于所有方案的最小值ans,如果小就替换
		return ;
	}
	for(int i=0;i<4;i++){
		int xx=dx[i]+x;//新的x值
		int yy=dy[i]+y;//新的y值
		if(f[xx][yy]){//如果是有颜色的
			if(f[xx][yy]==f[x][y])//如果颜色相同,直接不废钱,走过去就是了
				dfs(xx,yy,sum,false);//继续搜索
			else
				dfs(xx,yy,sum+1,false);//换个颜色
		}
		else if(!f[xx][yy] && !magic){//如果必须用魔法且可以用魔法
			f[xx][yy]=f[x][y];//替换
			dfs(xx,yy,sum+2,true);//继续搜索
			f[xx][yy]=0;//回溯一步
		}
	}
}
int main(){
	ans=INF;//现将ans设为无穷大
	memset(a,0x3f,sizeof(a));//初始化
	scanf("%d%d",&m,&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d%d",&x,&y,&c);//输入
		f[x][y]=c+1;//将f[x][y]存为颜色
	}
	dfs(1,1,0,false);//开始搜索
	if(ans==INF)//如果不能走到最后一格
		cout<<-1;//输出-1
	else//否则有解
	    cout<<ans;//输出最优解ans
	return 0;//圆满结束!!!
}

猜你喜欢

转载自blog.csdn.net/qq_42875611/article/details/83096740