Problem 2250 不可能弹幕结界
Accept: 5 Submit: 13
Time Limit: 1000 mSec Memory Limit : 65536 KB
Problem Description
咲夜需要穿过一片弹幕区,由于咲夜发动了符卡“The World”,所以弹幕是静止的。这片弹幕区以一个n*m的矩阵的形式给出。
‘.’表示这个位置是安全的,’x’表示这个位置上是有子弹的,禁止通行。咲夜每次能向左、右、下三个方向的相邻格子走,但是不能向上走。 同时由于时间有限,咲夜在进入每一行之后最多只能横向走k步。你可以简单地认为我们的目标就是从第0行走到第n+1行,起点和终点可以是在第0行和第n+1行的任意位置,当然第0行和第n+1行都是没有弹幕的。
然而这是号称不可能的弹幕结界,所以咲夜很可能无法穿过这片弹幕,所以咲夜准备了一个只能使用一次的技能,纵向穿越,她可以从任意位置直接穿越到另外任意一行的同一个位置(所在列不变),当然她只能向下穿越,不能向上穿越。穿越的距离越远,耗费的资源自然越多,所以她想知道最短的穿越距离,才能使她成功通过这片弹幕区。
Input
输入包含多组数据。
对于每组数据:
第一行输入三个整数n,m,k,如上所述。
接下下输入一个n×m的矩阵,’.’表示当前这格没有子弹,是安全的,’x’表示这各有子弹,禁止通行。
N<=1000,k<=m<=1000
Output
对于每组数据输出一个整数,表示最短的穿越距离。
Sample Input
6 5 2 x.x.. ..xx. .xxx. xx.xx xx..x ..x.x 4 4 1 .xxx .xxx ...x xx.x
Sample Output
3 2
Hint
对于第一组样例,最优解是从第一行第二列走到第三行第一列,然后跳到第6行第一列,穿越距离为(6 – 3) = 3。
long long类型请用%I64d输出
Source
FOJ有奖月赛-2017年4月(校赛热身赛)
/** 题目:Problem 2250 不可能弹幕结界 链接:http://acm.fzu.edu.cn/problem.php?pid=2250 题意:看原题。 思路: dtu[i][j]表示从底向上,不穿越能够到达的位置。 utd[i][j]表示从上到下,不穿越能够到达的位置。 然后枚举每一列,对每一列进行差值处理;取最小值。 */ #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <set> #include <vector> #include <cmath> using namespace std; typedef long long ll; typedef unsigned long long ull; const int inf = 0x3f3f3f3f; const int maxn = 1e5+10; const double eps = 1e-6; char a[1004][1004]; int dtu[1004][1004]; int utd[1004][1004]; int lt[1004][1004], rt[1004][1004]; ///预处理每个位置最左最右可达的地方。 int n, m, k; void init() { memset(lt, -1, sizeof lt); memset(rt, -1, sizeof rt); for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ if(a[i][j]=='.'){ lt[i][j] = lt[i][j-1]+1; } } for(int j = m; j >= 1; j--){ if(a[i][j]=='.'){ rt[i][j] = rt[i][j+1]+1; } } } } int Min(int a,int b) { return a>b?b:a; } int Max(int a,int b) { return a>b?a:b; } void dfsdtu(int x,int y) { if(x==1){ dtu[x][y] = 1; return ; } dtu[x][y] = 1; if(a[x-1][y]=='x') return ; for(int i = Max(y-lt[x-1][y],y-k); i <= Min(y+rt[x-1][y],y+k); i++){ if(dtu[x-1][i]) break; dfsdtu(x-1,i); } for(int i = Min(y+rt[x-1][y],y+k); i >= Max(y-lt[x-1][y],y-k); i--){ if(dtu[x-1][i]) break; dfsdtu(x-1,i); } } void dfsutd(int x,int y) { if(x==n){ utd[x][y] = 1; return ; } utd[x][y] = 1; if(a[x+1][y]=='x') return ; for(int i = Max(y-k,y-lt[x+1][y]); i <= Min(y+rt[x+1][y],y+k); i++){ if(utd[x+1][i]) break; dfsutd(x+1,i); } for(int i = Min(y+rt[x+1][y],y+k); i >= Max(y-lt[x+1][y],y-k); i--){ if(utd[x+1][i]) break; dfsutd(x+1,i); } } int main() { while(scanf("%d%d%d",&n,&m,&k)!=EOF) { for(int i = 1; i<= n; i++){ scanf("%s",a[i]+1); } init(); memset(dtu, 0, sizeof dtu); memset(utd, 0, sizeof utd); for(int i = 1; i <= m; i++){ if(a[n][i]=='.'){ dfsdtu(n,i);//由底向上 } } for(int i = 1; i <= m; i++){ if(a[1][i]=='.'){ dfsutd(1,i);//由上到下 } } int ans = n+1; for(int i = 1; i <= m; i++){ int dt = n+1, ut = 0; for(int j = 1; j <= n; j++){ if(dtu[j][i]){ dt = j; } if(utd[j][i]){ ut = j; } if(dt>ut){ ans = Min(ans,dt-ut); } ans = Min(ans,dt); ans = Min(ans,n+1-ut); if(dt==1||ut==n) ans = 0; } } printf("%d ",ans); } return 0; }