1. 程式人生 > >2017NOIP 普及組T3 棋盤

2017NOIP 普及組T3 棋盤

棋盤

【問題描述】

有一個m × m的棋盤,棋盤上每一個格子可能是紅色、黃色或沒有任何顏色的。你現在 要從棋盤的最左上角走到棋盤的最右下角。
  任何一個時刻,你所站在的位置必須是有顏色的(不能是無色的) ,你只能向上、下、 左、右四個方向前進。當你從一個格子走向另一個格子時,如果兩個格子的顏色相同,那你 不需要花費金幣;如果不同,則你需要花費 1 個金幣。
  另外,你可以花費 2 個金幣施展魔法讓下一個無色格子暫時變為你指定的顏色。但這個 魔法不能連續使用,而且這個魔法的持續時間很短,也就是說,如果你使用了這個魔法,走 到了這個暫時有顏色的格子上,你就不能繼續使用魔法;只有當你離開這個位置,走到一個 本來就有顏色的格子上的時候,你才能繼續使用這個魔法,而當你離開了這個位置(施展魔 法使得變為有顏色的格子)時,這個格子恢復為無色。 
  現在你要從棋盤的最左上角,走到棋盤的最右下角,求花費的最少金幣是多少?

【輸入格式】

輸入檔名為 chess.in。
  資料的第一行包含兩個正整數 m,n,以一個空格分開,分別代表棋盤的大小,棋盤上 有顏色的格子的數量。
  接下來的 n 行,每行三個正整數 x,y,c,分別表示座標為(x,y)的格子有顏色 c。 其中 c=1 代表黃色,c=0 代表紅色。相鄰兩個數之間用一個空格隔開。
  棋盤左上角的座標 為(1, 1),右下角的座標為(m, m)。 棋盤上其餘的格子都是無色。保證棋盤的左上角,也就是(1,1)一定是有顏色的。

【輸出格式】

輸出檔名為 chess.out。
  輸出一行,一個整數,表示花費的金幣的最小值,如果無法到達,輸出-1。

【輸入輸出樣例 1】

input

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

output

8 

見選手目錄下的 chess/chess1.in 和 chess/chess1.ans。 
  20171214102435_18846.png
  從(1,1)開始,走到(1,2)不花費金幣 
  從(1,2)向下走到(2,2)花費 1 枚金幣 
  從(2,2)施展魔法,將(2,3)變為黃色,花費 2 枚金幣 
  從(2,2)走到(2,3)不花費金幣 
  從(2,3)走到(3,3)不花費金幣 
  從(3,3)走到(3,4)花費 1 枚金幣
  從(3,4)走到(4,4)花費 1 枚金幣 
  從(4,4)施展魔法,將(4,5)變為黃色,花費 2 枚金幣, 
  從(4,4)走到(4,5)不花費金幣 
  從(4,5)走到(5,5)花費 1 枚金幣 
  共花費 8 枚金幣。 

【輸入輸出樣例 2】

input

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

output

-1 

見選手目錄下的 chess/chess2.in 和 chess/chess2.ans。

【輸入輸出樣例 2 說明】 
  20171214104505_83113.png
  從(1,1)走到(1,2),不花費金幣 
  從(1,2)走到(2,2),花費 1 金幣 
  施展魔法將(2,3)變為黃色,並從(2,2)走到(2,3)花費 2 金幣 
  從(2,3)走到(3,3)不花費金幣 
  從(3,3)只能施展魔法到達(3,2),( 2,3),( 3,4),(4,3) 
  而從以上四點均無法到達(5,5),故無法到達終點,輸出-1

【輸入輸出樣例 3】 
  見選手目錄下的 chess/chess3.in 和 chess/chess3.ans。

【資料規模與約定】

對於 30%的資料,1 ≤ m ≤ 5, 1 ≤ n ≤ 10。
  對於 60%的資料,1 ≤ m ≤ 20, 1 ≤ n ≤ 200。
  對於 100%的資料,1 ≤ m ≤ 100, 1 ≤ n ≤ 1,000。

時間限制:1s

空間限制:256MB

解題思路:

就是dfs加上剪枝,實際上特別簡單,只需要四個方向都走一遍。就相當於暴搜。

程式碼:

#include <bits/stdc++.h>
using namespace std;
int color[102][102],cost[102][102];
int m,n;
void dfs(int x,int y,int pre_x,int pre_y,int pre_magic)
{
	int magic=0,tmp_cost,tmp_color;
	if(x==0||y==0||x==m+1||y==m+1)
		return;
	if(pre_magic==1&&color[x][y]==-1)
		return;
	if(pre_magic==0&&color[x][y]!=-1)
	{
		if(color[x][y]!=color[pre_x][pre_y])
			tmp_cost=cost[pre_x][pre_y]+1;
		else
			tmp_cost=cost[pre_x][pre_y];
	}
	else if(color[x][y]==-1&&pre_magic==0)
	{
		magic=1;
		tmp_cost=cost[pre_x][pre_y]+2;
	}
	else if(pre_magic==1&&color[x][y]!=-1)
	{
		if(color[x][y]!=color[pre_x][pre_y])
			tmp_cost=cost[pre_x][pre_y]+1;
		else
			tmp_cost=cost[pre_x][pre_y];
	}
	if(cost[x][y]!=-1&&tmp_cost>=cost[x][y])
		return;
	cost[x][y]=tmp_cost;
	if(magic==1)
		color[x][y]=color[pre_x][pre_y];
	if(pre_magic==1)
	{
		tmp_color=color[pre_x][pre_y];
		color[pre_x][pre_y]=-1;
	}
	dfs(x+1,y,x,y,magic);
	dfs(x-1,y,x,y,magic);
	dfs(x,y+1,x,y,magic);
	dfs(x,y-1,x,y,magic);
	if(magic==1)
		color[x][y]=-1;
	if(pre_magic==1)
		color[pre_x][pre_y]=tmp_color;
}
int main()
{
	int i,j,x,y,c;
	scanf("%d %d",&m,&n);
	memset(cost,0xff,sizeof(cost));
	memset(color,0xff,sizeof(color));
	cost[1][1]=0;
	for(i=0;i<n;i++)
	{
		scanf("%d %d %d",&x,&y,&c);
		color[x][y]=c;
	}
	dfs(1,2,1,1,0);
	dfs(2,1,1,1,0);
	printf("%d",cost[m][m]);
	return 0;
}