洛谷 P7995 [USACO21DEC] Walking Home B

本文讨论了奶牛Bessie在N×N方阵中从草地到牛棚的路径问题,考虑了改变行走方向的限制。文章介绍了暴力搜索、剪枝策略以及记忆化搜索来优化计算Bessie的不同路线数量,重点在于减少重复状态和提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

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

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

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

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

分析

搜索+剪枝……

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

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

代码

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

#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;
}
/*

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值