[USACO21DEC] Walking Home B

题目描述

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

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

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

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

输入格式

每个测试用例的输入包含 TT 个子测试用例,每个子测试用例描述了一个不同的农场,并且必须全部回答正确才能通过整个测试用例。输入的第一行包含 TT(1 \leq T \leq 501≤T≤50)。每一个子测试用例如下。

每个子测试用例的第一行包含 NN 和 KK。

以下 NN 行每行包含一个长为 NN 的字符串。每个字符为 \texttt{.}.,如果这一格是空的,或 \texttt{H}H,如果这一格中有草堆。输入保证农场的左上角和右下角没有草堆。

输出格式

输出 TT 行,第 ii 行包含在第 ii 个子测试用例中 Bessie 可以选择的不同的路线数量。

样例 #1

样例输入 #1

7
3 1
...
...
...
3 2
...
...
...
3 3
...
...
...
3 3
...
.H.
...
3 2
.HH
HHH
HH.
3 3
.H.
H..
...
4 3
...H
.H..
....
H...

Copy

样例输出 #1

2
4
6
2
0
0
6

Copy

提示

【样例解释】

我们将使用一个由字符 D 和 R 组成的字符串来表示 Bessie 的路线,其中 D 和 R 分别表示 Bessie 向下(down)或向右(right)移动。

第一个子测试用例中,Bessie 的两条可能的路线为 DDRR 和 RRDD。

第二个子测试用例中,Bessie 的四条可能的路线为 DDRR,DRRD,RDDR 和 RRDD。

第三个子测试用例中,Bessie 的六条可能的路线为 DDRR,DRDR,DRRD,RDDR,RDRD 和 RRDD。

第四个子测试用例中,Bessie 的两条可能的路线为 DDRR 和 RRDD。

第五和第六个子测试用例中,Bessie 不可能回到牛棚。

第七个子测试用例中,Bessie 的六条可能的路线为 DDRDRR,DDRRDR,DDRRRD,RRDDDR,RRDDRD 和 RRDRDD。

【数据范围】

  • 测试点 2 满足 K = 1K=1。
  • 测试点 3-5 满足 K = 2K=2。
  • 测试点 6-10 满足 K = 3K=3。

思路 

先用一个四位数组来表示数:f[i][j][k][l],i,j表示位置,k为转了几次弯,l为上一步朝那边。

这样就可以得到两个公式:

f[i][j][k][0]+=(f[i-1][j][k][0]+f[i][j-1][k-1][1]);

 f[i][j][k][1]+=(f[i][j-1][k][1]+f[i-1][j][k-1][0]);

当然,0是例外,要用特判公式:

f[i][j][0][0]+=f[i-1][j][0][0];

f[i][j][0][1]+=f[i][j-1][0][1];

代码见下:

#include<bits/stdc++.h>
using namespace std;
long long int d=1e7,wl[]={9,2,5,5,4,5,6,3,7,6};
long long int f[51][51][51][51];
long long int z[10000000],sd,g[10000000],o[10000000],uss[1001][1001];
long long int n,m,mo=1e9+7;
long long int s=10;
long long int sf=1,sg=s,sh,tt=9e8,l,k;
char iio;
struct ll{
	int a,b,c;
}v[1023445];
bool qp(ll a,ll b){
	return a.a<b.a;
}
int main(){
    cin>>sh;
    for(int op=1;op<=sh;op++){
    	cin>>n>>k;
    	long long ans=0;
    	memset(uss,0,sizeof(uss)); 
    	memset(f,0,sizeof(f));
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=n;j++){
    			cin>>iio;
    			if(iio=='.') uss[i][j]=1;
    			else uss[i][j]=0;
			}
		}
		f[1][1][0][1]=f[1][1][0][0]=1;
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=n;j++){
				if(uss[i][j]==1){
					f[i][j][0][0]+=f[i-1][j][0][0];
					f[i][j][0][1]+=f[i][j-1][0][1];					
					for(int k1=1;k1<=3;k1++){
						f[i][j][k1][0]+=(f[i-1][j][k1][0]+f[i][j-1][k1-1][1]);
						f[i][j][k1][1]+=(f[i][j-1][k1][1]+f[i-1][j][k1-1][0]);			
					}					
				}
			}
		}		
		for(int kx=0;kx<=k;kx++){	
			ans+=(f[n-1][n][kx][0]+f[n][n-1][kx][1]);
		}	
		cout<<ans<<endl;	
	}	
	return 0;
}

 

  • 11
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值