2020牛客寒假算法基础集训营3 B 牛牛的DRB迷宫II二进制详解

2020牛客寒假算法基础集训营3 B 牛牛的DRB迷宫II
B 牛牛的DRB迷宫II
在这里插入图片描述
输入:

25

输出:

5 5
RBBBR
BBBBB
BBBDB
BDBBB
RBBBB

题解
由图求方案数,我们可以用DP求出来。但是由方案数构造图,怎么做呢?在做A题DP时我们就能体会到,这个图的构造(看题解知道的 )。一般这种构造题,我们都可以往二进制方向上想,因为二进制可以构造任何数!

官方题解不是很懂就看了这位大佬的题解报告:https://blog.csdn.net/weixin_43890662/article/details/104226161

我们可以构造一个二进制编码器,斜对角线上的方案数恰好是1,2,3,4,8,16,32…,用二进制可以拼出所有的数字,所以一定能造的出来。(引用官方题解)
题解的图是这样的,即主对角线上的格子都为B,它的上一个点为D,下一个点为R,其余我们都初始化为R。那么一开始这样的初始图的方案数为2n-1个。
在这里插入图片描述
那么我们输入的k怎么可能一定就是2的整数次方呢?
比如65?
我们既然是一个二进制编码器,先写出65的二进制表示为:1000001
我们可以直接用初始图表示64(1000000),那么那个‘1’就是我们要另外表示的。这条路径怎么怎加呢?
64:
在这里插入图片描述
-》65:
在这里插入图片描述
增加一条这样的路径(第1列向下,到n行后向右),即组成k的二进制数的某位出现"1"就给该位增加一条这样的路径,就相当于把k的二进制数写出来了,故叫:“二进制编码器”

现在给出AC代码:(0特判不要忘了,有详细注释)

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
const ll mod=1e9+7;
int book[35];//判断k的哪位数是1 
char e[55][55];
int main(void)
{
	ll k;
	scanf("%lld",&k);
	k%=mod;
	int s=k;
	int n=0;
	while(k)
	{
		n++;
		if(k&1)
		book[n]=1;
		k>>=1;
	}//二进制可以构成任何数 
	//2^n<=k;
	n++; 
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++)
		if(i==j)
		{
			e[i][j]='B';
		}
		else if(j==i+1&&j<n)
		e[i][j]='D';
		else
		e[i][j]='R';
	}//构造最初的二进制图即对角线为B,上一个为D,下一个为R,其余全为R的图 
	for(int i=n;i>=1;i--){ 
		if(book[i]==1)
		{
			e[i+1][i]='B';//由R变为B,因为要向下
			for(int j=i+2;j<=n;j++)
			e[j][i]='D';//向下
			for(int j=i;j<=n;j++)
			e[n][j]='R';//向右 
		}//当前位为1,要增加路,实际增加的路数为2^i条 
	}
	//输出:
	
	if(s==0)//特判 不要忘了 
	{
		printf("%d %d\n",2,2); 
		printf("RR\nRR\n");
		return 0;
	}
	printf("%d %d\n",n,n);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++)
		printf("%c",e[i][j]);
		printf("\n");
	} 
	return 0;
}
发布了68 篇原创文章 · 获赞 15 · 访问量 9001

猜你喜欢

转载自blog.csdn.net/qq_43791377/article/details/104243035