[BZOJ] 1616: [Usaco2008 Mar]Cow Travelling游荡的奶牛
1616: [Usaco2008 Mar]Cow Travelling游荡的奶牛
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1312 Solved: 736
[Submit][Status][Discuss]
Description
奶牛们在被划分成N行M列(2 <= N <= 100; 2 <= M <= 100)的草地上游走,试图找到整块草地中最美味的牧草。Farmer John在某个时刻看见贝茜在位置 (R1, C1),恰好T (0 < T <= 15)秒后,FJ又在位置(R2, C2)与贝茜撞了正着。 FJ并不知道在这T秒内贝茜是否曾经到过(R2, C2),他能确定的只是,现在贝茜在那里。 设S为奶牛在T秒内从(R1, C1)走到(R2, C2)所能选择的路径总数,FJ希望有一个程序来帮他计算这个值。每一秒内,奶牛会水平或垂直地移动1单位距离(奶牛总是在移动,不会在某秒内停在它上一秒所在的点)。草地上的某些地方有树,自然,奶牛不能走到树所在的位置,也不会走出草地。 现在你拿到了一张整块草地的地形图,其中'.'表示平坦的草地,'*'表示挡路的树。你的任务是计算出,一头在T秒内从(R1, C1)移动到(R2, C2)的奶牛可能经过的路径有哪些。
Input
* 第1行: 3个用空格隔开的整数:N,M,T
* 第2..N+1行: 第i+1行为M个连续的字符,描述了草地第i行各点的情况,保证 字符是'.'和'*'中的一个 * 第N+2行: 4个用空格隔开的整数:R1,C1,R2,以及C2
Output
* 第1行: 输出S,含义如题中所述
Sample Input
...*.
...*.
.....
.....
1 3 1 5
输入说明:
草地被划分成4行5列,奶牛在6秒内从第1行第3列走到了第1行第5列。
Sample Output
奶牛在6秒内从(1,3)走到(1,5)的方法只有一种(绕过她面前的树)。
HINT
Source
Analysis
蒟蒻只看出这是暴搜 qwq
首先一个限定 T 步的DFS(这样可以防止路径重复)
证明:显然(不会证啊qwq)
定义计数图 cnt [ x ] [ y ] ,保存可到达点 ( x , y ) 的路径总数
然后某一次路径搜索在哪里终结,就在对应点的计数图上 +1
好的,6000+ms 为某位大佬的权限号贡献一个TLE
考虑剪枝
如果一条路径无法到达目的地,那么这条路径显然是可以剪枝剪掉的
定义最短距离图 Tracing [ x ] [ y ] ,保存目的地到点 ( x , y ) 的最短距离
如果在DFS的某个状态中,剩余的步数已经不够到达了,敢敢剪掉
上述算法用时 3288ms
然后我研究了一下其他人的版本
发现是一个什么都不是的DP
QwQ
定义 DP [ t ] [ x ] [ y ] 为第 t 秒可以到达点 ( x , y ) 的总路径数
那么我们可以暴力了
代码已Po
其实早先也有想到类似解法,但是如何防止新求出来的答案互相覆盖呢?(天真的我一直局限于用一张地图= =)
根据时间区别,不停绘制新地图,就类似上述的DP状态定义
还是太年轻啊,唉
DP用时:44ms
Code
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 5 const int dir[4][2] = {{0,1},{1,0},{-1,0},{0,-1}}; 6 7 int r,c,t,sx,sy,tx,ty; 8 int map[1000][1000]; 9 int DP[20][1000][1000]; 10 char str[1000]; 11 12 int main(){ 13 scanf("%d%d%d",&r,&c,&t); 14 for(int i = 1;i <= r;i++){ 15 scanf("%s",str); 16 for(int j = 1;j <= c;j++){ 17 if(str[j-1] == '.') map[i][j] = 1; 18 } 19 }scanf("%d%d%d%d",&sx,&sy,&tx,&ty); 20 21 DP[0][sx][sy] = 1; 22 23 for(int T = 1;T <= t;T++){ 24 for(int i = 1;i <= r;i++){ 25 for(int j = 1;j <= c;j++){ 26 for(int k = 0;k < 4;k++){ 27 int nowx = i+dir[k][0]; 28 int nowy = j+dir[k][1]; 29 if(!map[nowx][nowy]) continue; 30 DP[T][i][j] += DP[T-1][nowx][nowy]; 31 } 32 } 33 } 34 } 35 36 printf("%d",DP[t][tx][ty]); 37 38 return 0; 39 }
1 #include<cstdio> 2 #include<iostream> 3 #include<queue> 4 using namespace std; 5 6 struct node{ 7 int x,y,step; 8 }; 9 10 const int dir[4][2] = {{1,0},{0,1},{-1,0},{0,-1}}; 11 int r,c,t,sx,sy,tx,ty; 12 int map[1000][1000]; 13 int tracing[1000][1000]; 14 int cnt[1000][1000]; 15 bool book[1000][1000]; 16 char ctr; 17 18 void bfs(){ 19 queue<node> Q; 20 Q.push((node){tx,ty,0}); 21 tracing[tx][ty] = -1; 22 23 while(!Q.empty()){ 24 node now = Q.front(); 25 Q.pop(); 26 27 for(int i = 0;i < 4;i++){ 28 int nowx = now.x+dir[i][0]; 29 int nowy = now.y+dir[i][1]; 30 if((!tracing[nowx][nowy] || tracing[nowx][nowy] >= now.step+1) && map[nowx][nowy]){ 31 tracing[nowx][nowy] = now.step+1; 32 if(!book[nowx][nowy]){ 33 Q.push((node){nowx,nowy,now.step+1}); 34 book[nowx][nowy] = true; 35 } 36 } 37 } 38 book[now.x][now.y] = false; 39 } 40 } 41 42 void dfs(int nowx,int nowy,int step){ 43 if(step == t) cnt[nowx][nowy]++; 44 else{ 45 for(int i = 0;i < 4;i++){ 46 int x = nowx+dir[i][0]; 47 int y = nowy+dir[i][1]; 48 49 if(map[x][y] && step+tracing[x][y] <= t) dfs(x,y,step+1); 50 } 51 } 52 } 53 54 int main(){ 55 scanf("%d%d%d",&r,&c,&t); 56 for(int i = 1;i <= r;i++){ 57 for(int j = 1;j <= c;j++){ 58 cin >> ctr; 59 if(ctr == '.') map[i][j] = 1; 60 } 61 } 62 63 scanf("%d%d%d%d",&sx,&sy,&tx,&ty); 64 65 bfs(); 66 67 dfs(sx,sy,0); 68 69 printf("%d",cnt[tx][ty]); 70 71 // for(int i = 1;i <= r;i++){ 72 // /cout << endl; 73 // for(int j = 1;j <= c;j++){ 74 // printf("%d ",tracing[i][j]); 75 // } 76 // } 77 78 return 0; 79 }