[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
4 5 6...*.
...*.
.....
.....
1 3 1 5
輸入說明:
草地被劃分成4行5列,奶牛在6秒內從第1行第3列走到了第1行第5列。
Sample Output
奶牛在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)
[BZOJ] 1616: [Usaco2008 Mar]Cow Travelling遊蕩的奶牛