洛谷 P7995 [USACO21DEC] Walking Home B

发布时间:2024年01月17日

题目描述

奶牛 Bessie 正准备从她最喜爱的草地回到她的牛棚。

农场位于一个 N × N N \times N N×N 的方阵上( 2 ≤ N ≤ 50 2 \leq N \leq 50 2N50),其中她的草地在左上角,牛棚在右下角。Bessie 想要尽快回家,所以她只会向下或向右走。有些地方有草堆(haybale),Bessie 无法穿过;她必须绕过它们。

Bessie 今天感到有些疲倦,所以她希望改变她的行走方向至多 K K K 次( 1 ≤ K ≤ 3 1 \leq K \leq 3 1K3)。

Bessie 有多少条不同的从她最爱的草地回到牛棚的路线?如果一条路线中 Bessie 经过了某个方格而另一条路线中没有,则认为这两条路线不同。

分析

搜索+剪枝……

一个十分暴力的搜索是:记录转弯次数 c n t cnt cnt,和目前方向 p o s pos pos,每次搜索是判断方向是否与 p o s pos pos 相同,如果不同则 c n t cnt cnt 要加 1 1 1,但是我们会发现除了样例这个程序其他点都过不了,所以考虑剪枝:

  • 如果走到点 ( x , y ) (x,y) (x,y) 时,转弯次数已经大于 k k k,就进行剪枝。
  • 如果走到点 ( x , y ) (x,y) (x,y) 时,转弯次数已经等于 k k k,但是 x , y x,y x,y 都不等于 n n n,则此时至少还需一次转弯,进行剪枝。
  • 我们发现搜索树里有很多重复状态,所以考虑记忆化搜索,设 d p x , y , c n t , n o w dp_{x,y,cnt,now} dpx,y,cnt,now? 表示走到点 ( x , y ) (x,y) (x,y) 已经转了 c n t cnt cnt 次弯,当前方向是 n o w now now

代码

这里给出不用记忆化搜索的代码。

#include <bits/stdc++.h>
#define debug puts("Y")
#define int long long

using namespace std;

const int N = 55;
char c[N][N];
int n, k, cnt;
int dx[] = {0, 1}, dy[] = {1, 0};//0:右 1:下 

void dfs(int x, int y, int cir, int pre){
	if(c[x][y] == 'H' || cir > k + 1 || (x != n && y != n && cir == k + 1)){//由于第一次搜索时不好处理,所以直接将转弯次数看成k+1即可
		return ;
	}
	if(x == n && y == n){
		cnt ++;
		return ;
	}
	for(int i = 0; i < 2; i ++){
		int nx = x + dx[i], ny = y + dy[i];
		if(i != pre){
			dfs(nx, ny, cir + 1, i);
		}else{
			dfs(nx, ny, cir, i);
		}
	}
}

void solve(){
	cnt = 0;
	cin >> n >> k;
	memset(c, 'H', sizeof c);//在外面包一圈障碍物,这样就不用判越界了
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			cin >> c[i][j];
		}
	}
	dfs(1, 1, 0, 114514);
	cout << cnt << "\n";
}

signed main(){
	int T;
	for(cin >> T; T; T --){
		solve();
	}
	return 0;
}
/*

*/

文章来源:https://blog.csdn.net/zc2000911/article/details/135651560
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。