1. 程式人生 > >Jzoj P5793 小S練跑步___bfs+dp

Jzoj P5793 小S練跑步___bfs+dp

題目大意:

給出一副n*m的圖,每個點都有限制不能走的方向,不能越界,遇到障礙後會停止,問從點(1,1)走到點(n,m)的最少轉彎次數。

n,m≤500

分析:

f[i][j][k]f[i][j][k]表示到達了點(i,j)(i,j)下一步走的方向為kk時的最少轉彎次數, 然後用bfs去更新即可

程式碼:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define N 505

using namespace std;

const int inf = 0x3f3f3f;
const int px[4] = {-1, 0, 0, 1};
const int py[4] = {0, -1, 1 ,0};
queue <int> dx, dy, nt, num;

int f[N][N][5], n, m;
bool a[N][N][5];
char s[N];

bool check(int mx, int my)
{
    if (mx < 1 || mx > n || my < 1 || my > n) return 1;
    if (a[mx][my][4]) return 1;
	return 0;	
}

int main()
{
	freopen("run.in","r",stdin);
	freopen("run.out","w",stdout);
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++)
	{
		 scanf("%s", s + 1);
		 for (int j = 1; j <= m; j++) 
		 {
		 	  if (s[j] == 'U') a[i][j][0] = 1;
		 	  if (s[j] == 'L') a[i][j][1] = 1;
		 	  if (s[j] == 'R') a[i][j][2] = 1;
		 	  if (s[j] == 'D') a[i][j][3] = 1;
		 	  if (s[j] == 'S') a[i][j][4] = 1;
		      for (int k = 0; k < 4; k++) f[i][j][k] = inf;
		 }
	}
	for (int i = 0; i < 4; i++) 
	     if (!a[1][1][i]) 
		 {
		 	  f[1][1][i] = 0;
		 	  dx.push(1), dy.push(1), nt.push(i);
		      while (dx.size())
		      {
		      	     int gc = nt.front();
		      	     int gx = dx.front();
		      	     int gy = dy.front();
		      	     dx.pop(), dy.pop(), nt.pop();
		      	     
		      	     int cx = gx + px[gc]; 
		      	     int cy = gy + py[gc];
		      	     if (check(cx, cy)) continue;
					 
					 for (int j = 0; j < 4; j++)
		      	     {
		      	     	  if (a[cx][cy][j]) continue;
		      	          int x = f[gx][gy][gc]; 
						  if (j != gc) x++;
						  if (f[cx][cy][j] > x)
						  {
						  	  f[cx][cy][j] = x;
						      dx.push(cx), dy.push(cy), nt.push(j);	
	       				  }
                     }
			  }
	     }
	int ans = min(f[n - 1][m][3], f[n][m - 1][2]);
	if (ans != inf) printf("%d\n", ans);
	           else printf("No Solution\n");
	return 0;
}