[BZOJ] 1616: [Usaco2008 Mar]Cow Travelling游荡的奶牛

1616: [Usaco2008 Mar]Cow Travelling游荡的奶牛

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 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

4 5 6
...*.
...*.
.....
.....
1 3 1 5

输入说明:

草地被划分成4行5列,奶牛在6秒内从第1行第3列走到了第1行第5列。

Sample Output

1

奶牛在6秒内从(1,3)走到(1,5)的方法只有一种(绕过她面前的树)。

HINT

 

Source

Silver

 

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 }
我试图在下面重新插一行,但是失败了,这样不符合行文顺序qwq(DP)
 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 }
不得不说虽然BZOJ用户体验奇差无比,但是这样的排版可以直接搞到cnblogs上超爽的(BFS+DFS)
posted @ 2017-09-02 12:13  Leviaton  阅读(133)  评论(0编辑  收藏  举报