1. 程式人生 > 實用技巧 >ICPC小米邀請賽 I.Walking Machine

ICPC小米邀請賽 I.Walking Machine

題目:

Given a maze of size n×m, where upper left corner is (1,1)
and lower right corner is (n, m). For each cell (x, y) , there is exactly one character c (c∈{W,A,S,D}) on it, denoting the moving restriction:

  • If c=W , you can only go up from this cell, specifically go from (x, y)to (x-1, y)
  • If c=A , you can only go left from this cell, specifically go from(x,y) to (x,y−1)
  • If c=S, you can only go down from this cell, specifically go from(x,y) to (x+1,y)
  • If c=D , you can only go right from this cell, specifically go from (x,y) to (x,y+1)

    We say one is out if x < 1 or x > n or y < 1 or y > m holds, now you should determine the number of cells that one can be out if start walking on it.

輸入描述:
The first line contains two integers n,m (1≤n,m≤1000), denoting the size of the maze.

Following n lines each contains a string of length m , where the j-th character in i-th line s(i, j) ( s (i,j)∈{W,A,S,D}) denotes the character on cell (i, j).
輸出描述:
Only one line containing one integer, denoting the number of cells that can make one out.

輸入
3 4
DDSD
AWAA
WASD

輸出
6
說明
The 6 cells are (1, 4),(2, 1),(3, 1),(3, 2),(3, 3),(3, 4) respectively.

題意:判斷一個迷宮中有幾個點可以走出去,每個點會有一個方向,也就是我們鍵盤上的WASD(向上、向左、向下、向右)

題解:我首先是把最外圍那圈能直接走出去的做一個標記(其實不用也行,可以直接搜),然後其他的點依次判斷是否能走出去,重點就是幾個剪枝,假如之前遍歷過的點並且不能走出,那麼這些所有的點下一次走到的時候肯定走不出去,如果之前遍歷的點可以走出去,那麼所有的點下次被走到時肯定肯定可以走出去。(bfs也可做)

程式碼:

#include<stdio.h> 
#include<iostream>
#include<string.h>
#include<stdlib.h>
using namespace std;
const int N = 1005;
char map[1005][1005];
int can[N][N], vis[N][N]; //vis:標記之前是否走過, can:是否一定可以走出去或者走不出去 
int cnt = 0;
int flag = 0;
int n, m;
void dfs(int x, int y)
{
	if(can[x][y] == 1) //如果之前已經遍歷過, 該點可以到達 
	{
		cnt++;
		flag = 1; //標記一下可以走出迷宮 
		return;
	}
	if(can[x][y] == -1) return; //該點不能走出去 
	if(vis[x][y])
	{
		can[x][y] = -1; //重複遍歷, 一定無法走出去 
		return;
	}
	if(map[x][y] == 'W' )
	{
		vis[x][y] = 1;
		dfs(x - 1,y);
		vis[x][y] = 0;
		if(flag == 0) can[x][y] = -1; //如果最後無法到達, 將此次遍歷過的所有點標為不可行 
		else can[x][y] = 1; //否則一定可以走出去(比賽的時候忘寫了,直接T) 
	}
	else if(map[x][y] == 'S')
	{
		vis[x][y] = 1;
		dfs(x + 1,y);
		vis[x][y] = 0;
		if(flag == 0) can[x][y] = -1;
		else can[x][y] = 1;
	}
	else if(map[x][y] == 'A' )
	{
		vis[x][y] = 1;
		dfs(x,y - 1);
		vis[x][y] = 0;
		if(flag == 0) can[x][y] = -1;
		else can[x][y] = 1;
	}
	else if(map[x][y] == 'D')
	{
		vis[x][y] = 1;
		dfs(x,y + 1);
		vis[x][y] = 0;
		if(flag == 0) can[x][y] = -1;
		else can[x][y] = 1;
	}
}

int main()
{
	freopen("cin.in", "r", stdin);
	freopen("cout.out", "w", stdout);
	memset(can, 0, sizeof(can));
	memset(vis, 0, sizeof(vis));
	scanf("%d%d", &n, &m);
	getchar();
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= m; j++)
		{
			scanf("%c", &map[i][j]);
			if(i == 1 || j == 1 || i == n || j == m)
			{
				if(j == 1 && map[i][j] == 'A') can[i][j] = 1;
				if(i == 1 && map[i][j] == 'W') can[i][j] = 1;
				if(j == m && map[i][j] == 'D') can[i][j] = 1;
				if(i == n && map[i][j] == 'S') can[i][j] = 1;	
			}
			
		}
		getchar();
	}
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= m; j++)
		{
			flag = 0;
			if(can[i][j] == 1) cnt++;
			else dfs(i, j);
		}
	}
	cout << cnt << endl;
	return 0;
}