【算法每日一练]-dfs (保姆级教程 篇9) #俄罗斯方块 #ABC Puzzle #lnc的工资

news2024/11/17 11:46:18

目录

今日知识点:

二维图形的状态压缩,存下所有的合法状态然后暴力遍历

dfs的优化剪枝

二项式定理

俄罗斯方块

ABC Puzzle

lnc的工资


        

                

俄罗斯方块

322D

题意:在4*4方格中分别给出3个俄罗斯方块,问是否可以经过旋转,平移操作恰好拼满整个4*4格子? 不能重叠和越界。

输入样例:

样例解释 

思路:

首先是如何存储图形以及变化后的图形,当然不仅要方便变换还要方便最后检查。然后就想到了状态压缩,一共最多16格子,最多需要16位就行。
也就是最大用2^16-1的数字即可表示这种状态,然后对3个俄罗斯方块一一组合遍历看看能否最4*4方格进行平铺。
    如何存入状态:4*4每个格子一一对应1~16的位置,有效的格子坐标转换到一维的二进制位置进行更新。(1<<?和二进制数字相或)平移操作就是把所有位置移动一下。旋转不过是对原字符串进行适当变化,然后把所有的变换后的有效状态存下来。
    如何遍历结果:将3个状态数字相或,然后看是否全是1即可,判断是否等于1<<(4*4)-1就行
要注意不能有重叠:任意两个状态数字不能相与必须为0

非常好的一道状态压缩题!!!

#include <bits/stdc++.h>
using namespace std;
const int SIZE=4;
void rotate(string s[]){//旋转函数(顺时针旋转)
	char tmp[SIZE][SIZE];
	for(int i=0;i<SIZE;i++){
		for(int j=0;j<SIZE;j++){
			tmp[j][SIZE-1-i]=s[i][j];//i为0时:tmp[0,1,2][2]=s[0][0,1,2]
		}//相当于横着的变成竖着的
	}
	for(int i=0;i<SIZE;i++){
		s[i]=string (tmp[i],tmp[i]+SIZE);//string函数:从第一个字符位置开始转换,长度位SIZE
	}
}
bool valid(int x){return x>=0&&x<SIZE;}
int get(string s[],int dx,int dy){
	int ret=0;
	for(int x=0;x<SIZE;x++){
		for(int y=0;y<SIZE;y++){
			if(s[x][y]=='#'){
				int xx=x+dx,yy=y+dy;
				if(!valid(xx)||!valid(yy)){//不能越界,函数重用嘛
					return -1;
				}
				ret |=1<<(xx*4+yy);//xx*4+yy是把每个对应格子给算成数字,然后和ret或运算修改对应位置(有1出1)
			}
		}
	}
	return ret;
}
vector<int>add(){
	vector<int>ret;//用于存放状态
	string s[SIZE];
	for(int i=0;i<SIZE;i++)cin>>s[i];//输入字符阵列
	
	for(int num=0;num<4;num++){//执行四个旋转操作
		for(int dx=-3;dx<=3;dx++){//执行平移操作,要注意的是不仅要向右平移,还要向左平移
			for(int dy=-3;dy<=3;dy++){//向上和下平移
				int v=get(s,dx,dy);//用一个数字来存下次时旋转和平移后的结果(1~16个1的状态,只需要16位即可最多2^16-1)
				if(v>=0){ret.push_back(v);
				}
			}
		}
		rotate(s);//旋转一下
	}
	return ret;//返回这个俄罗斯方块对应的全部状态
}
int main(){
	vector<int>mask[3];
	for(int id=0;id<3;id++){
		mask[id]=add();//输入字符阵列,获取四个方向,所有平移结果的状态数字,存入mask中
	}
	for(int x:mask[0]){//检查所有的情况有没有能成立的
		for(int y:mask[1]){
			for(int z:mask[2]){
				if((x|y|z)+1!=(1<<SIZE*SIZE))continue;//x|y|z就可以把1的位置全部标出来(要等于2^16-1嘛)
				if(x&y)continue;
				if(x&z)continue;
				if(z&y)continue;
				cout<<"Yes\n";
				return 0;
			}
		}
	}
	cout<<"No\n";
}

        

         

ABC Puzzle

326D

题意:给两个长n的仅由ABC组成的字符串s1,s2,是否在n*n阵列中满足以下条件,若满足则输出,不满足输出No

  条件1:每行每列仅包含一个A,一个B,一个C           (3<=n<=5)
  条件2:第i行最左边的字符恰好是s1的第i个字符
  条件3:第i列最上边的字符恰好是s2的第i个字符

输入样例:             输出样例:
5                             Yes
ABCBC                    AC..B
ACAAB                    .BA.C
                                C.BA.
                                BA.C.
                                ..CBA
思路:

一道比较恶心的dfs题。

说一下dfs思路吧:

依次放每个格子可以放.  也可以放A或B或C这四种选择。然后全部放完就检查一下即可。因为走错就要回溯,这最大妥妥的4^25根本过不去。首先主要到每行每列最多两个. 那么就要加以剪枝。

设置cnt[0][i][?]表示第i行已经有几个. 字符,cnt[1][i][?]对应第i列已经有几个. 字符?(剪枝1)

if(cnt[0][x]['.']<n-3&&cnt[1][y]['.']<n-3){//这是放"."的情况,每行列最多放两个,因为只放一次,所以if语句即可
	an[x][y]='.';
	cnt[0][x]['.']++;cnt[1][y]['.']++;
	dfs(x,y+1);
	cnt[0][x]['.']--;cnt[1][y]['.']--;
	}

 然后是放置3种字母。首先是看看同行是否已经有该字符。同样设置cnt[0][x][c]代表第x行是否有该字符,cnt[1][y][c]代表第y行是否有该字符。(剪枝2)

        接着是看是否和原字符串的对应位置匹配。第一个字符串对应x行,第二个字符串对应y列,我们如果swap后如果传入的是s[0][x]是0,那么自动返回1,这种情况就对应已经有了开头字符了。如果没有开头字符那就直接和开头字符比较看是否相同。(剪枝3)

for(char c='A';c<='C';c++){//放3种字母
	if(cnt[0][x][c]==0&&cnt[1][y][c]==0){//第x行y列是否都没有该字符
		if(match(s[0][x],c)&&match(s[1][y],c)){
//开头都确定,开头一个确定另一个不确定但相等,开头都不确定但都相等
			an[x][y]=c;
			char tmp=0,tmp2=0;
			swap(tmp,s[0][x]);//0和0交换(开头已经确定),0和非0交换(开头未确定变已确定)
			swap(tmp2,s[1][y]);
			cnt[0][x][c]++;cnt[1][y][c]++;
			dfs(x,y+1);
			cnt[1][y][c]--;cnt[0][x][c]--;//失败,回溯(回溯尽量去swap,这样更容易恢复状态)
			swap(tmp,s[0][x]);//交换回来
			swap(tmp2,s[1][y]);
			}
		}
	}

好了,经过以上的剪枝,这个dfs就能过去了 

#include <bits/stdc++.h>
using namespace std;
int n;
int cnt[2][5][128];//cnt[0][i][?]表示第i行已经有几个?字符(ASCII),cnt[1][i][?]对应相关列
char an[5][7];//答案阵列
string s[2];
bool match(char c1,char c2){
	if(!c1)return 1;//如果说传过来的s[0,1][?]对应第?行,列已经有开头字符了(将会传过来0),那就直接返回正确
	return c1==c2;//否则就去比较这两个字符
}
//void型dfs 中return其实可有可无,其实就相当于是函数的continue功能,是为了防止进入走后面的代码,引发错误!
//dfs中的标记变量,一定要设置为局部变量,避免被别的dfs给修改
void dfs(int x,int y){//其实每个格子都有4种选择,不见得非ABC就要回溯,一定要细心
	if(x==n){
		cout<<"Yes\n";
		for(int i=0;i<n;i++)cout<<an[i]<<'\n';
		exit(0);//任务完全直接结束
	}
	if(y==n){dfs(x+1,0);return ;}
	if(cnt[0][x]['.']<n-3&&cnt[1][y]['.']<n-3){//这是放"."的情况,每行列最多放两个,因为只放一次,所以if语句即可
		an[x][y]='.';
		cnt[0][x]['.']++;cnt[1][y]['.']++;
		dfs(x,y+1);
		cnt[0][x]['.']--;cnt[1][y]['.']--;
	}
	for(char c='A';c<='C';c++){、、放3种字母
		if(cnt[0][x][c]==0&&cnt[1][y][c]==0){//第x行y列是否都没有该字符
			if(match(s[0][x],c)&&match(s[1][y],c)){
//开头都确定,开头一个确定另一个不确定但相等,开头都不确定但都相等
				an[x][y]=c;
				char tmp=0,tmp2=0;
				swap(tmp,s[0][x]);//0和0交换(开头已经确定),0和非0交换(开头未确定变已确定)
				swap(tmp2,s[1][y]);
				cnt[0][x][c]++;cnt[1][y][c]++;
				dfs(x,y+1);
				cnt[1][y][c]--;cnt[0][x][c]--;//失败,回溯(回溯尽量去swap,这样更容易恢复状态)
				swap(tmp,s[0][x]);//交换回来
				swap(tmp2,s[1][y]);
			}
		}
	}
}
int main(){
	cin>>n;
	for(int i=0;i<2;i++)cin>>s[i];
	dfs(0,0);
	cout<<"No\n";
}

        

        

lnc的工资

326E

题意:Inc的工资:给出n面的骰子,i对应a[i]元。问最终获得钱的期望是多少(结果对998244353取模)

规则如下:起初x=0,掷出y(>x)则给出a[y]元,同时x变成y,重复操作,直到y(<=x)时结束游戏

思路:

我们先算出现i的概率:
对于第一次:必然是1/n;
第二次:只能从1~i-1过来,所以是(i-1)/n*(1/n),化简成(i-1)*1/n^2
第三次:前两次都恰好从1~i-1中选了两个数,所以是C(2,i-1)*1/n^3   依次类推

然后所有概率相加:∑(i-1,k=0) (1/n)*C(k,i-1)*(1/n)^k    

根据二项式定理转成∑(i-1,k=0) ((n+1)/n)^(i-1) 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD=998244353;
ll qpow(ll a,ll b){
	ll res=1;a%=MOD;
	while(b){
		if(b&1)res=(res*a)%MOD;
		a=(a*a)%MOD;
		b>>=1;
	}
	return res%MOD;
}
ll niyuan(ll x){
	return qpow(x,MOD-2);
}
int main(){
	int n;cin>>n;
	ll nn=niyuan(n);//nn为n的逆元,相当于1/n
	ll now=nn;//now即为当前的概率,最开始now就是i=1的概率
	ll ans=0;
	for(int i=1;i<=n;i++){
		int x;cin>>x;//输入每个a[i]
		ans=(ans+now*x)%MOD;//累加每个a[i]的期望
		now=now*(n+1)%MOD*nn%MOD;//求下一个a[i]的概率,只需要多乘一次(n+1)/n,也就是(n+1)*nn即可
	}	
	cout<<ans<<'\n';
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1372010.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电脑提示找不到msvcr100.dll的解决方法分享,只需四步即可搞定

“找不到msvcr100.dll”是一个常见的问题&#xff0c;许多人在使用计算机时都可能遇到过。这个文件是Microsoft Visual C 2010 Redistributable Package的一部分&#xff0c;包含了许多C运行库函数的实现。当我们在使用一些软件或游戏时&#xff0c;这些程序会调用msvcr100.dll…

鱼哥赠书活动第⑥期:《内网渗透实战攻略》看完这本书教你玩转内网渗透测试成为实战高手!!!!

鱼哥赠书活动第⑥期&#xff1a;《内网渗透实战攻略》 如何阅读本书&#xff1a;本书章节介绍&#xff1a;本书大致目录&#xff1a;适合阅读对象&#xff1a;赠书抽奖规则:往期赠书福利&#xff1a; 当今&#xff0c;网络系统面临着越来越严峻的安全挑战。在众多的安全挑战中&…

统计学-R语言-1

文章目录 统计学介绍基本类型数据和变量数据抽样总结 统计学介绍 统计学(statistics)是“数据的科学” 1.是用以收集数据、分析数据和由数据得出结论的一组概念、原则和方法。 2.统计学进行推断的基础是数据(data)。数据不仅仅限于数字&#xff0c;也可能是图表、视频、音频或…

OpenHarmony—编译构建指导

概述 OpenHarmony编译子系统是以GN和Ninja构建为基座&#xff0c;对构建和配置粒度进行部件化抽象、对内建模块进行功能增强、对业务模块进行功能扩展的系统&#xff0c;该系统提供以下基本功能&#xff1a; 以部件为最小粒度拼装产品和独立编译。支持轻量、小型、标准三种系…

DHSP和DNS

一、服务程序 1.1DHCP定义 DHCP&#xff08;动态主机配置协议&#xff09;是一个局域网的网络协议。指的是由服务器控制一段IP地址范围&#xff0c;客户机登录服务器时就可以自动获得服务器分配的IP地址和子网掩码。默认情况下&#xff0c;DHCP作为Windows Server的一个服务组…

第三次面试总结 - 吉云集团 - 全栈开发

&#x1f9f8;欢迎来到dream_ready的博客&#xff0c;&#x1f4dc;相信您对专栏 “本人真实面经” 很感兴趣o (ˉ▽ˉ&#xff1b;) 专栏 —— 本人真实面经&#xff0c;更多真实面试经验&#xff0c;中大厂面试总结等您挖掘 目录 总结&#xff08;非详细&#xff09; 面试内…

【办公技巧】Word中如何对齐选择题中的ABCD选项?

使用word文件制作试卷&#xff0c;如何将ABCD选项全部设置对齐&#xff1f;除了一直按空格或者Tab键以外&#xff0c;还有其他方法吗&#xff1f;今天分享如何将ABCD选项对齐。 首先&#xff0c;我们打开【替换和查找】&#xff0c;在查找内容输入空格&#xff0c;然后点击全部…

mysql之数据类型、建表以及约束

文章目录 一、CRUD1.1 SELECT(查询)1.1.1概念1.1.2语法(这里的都改为<>)1.1.3含义(这里的都改为<>) 1.2 INSERT(新增)1.2.1概念1.2.2语法1.2.3含义1.2.4 由INSERT 语句的两种形式可以看出: 1.3UPDATE(修改)1.3.1语法1.3.2含义 1.4DELETE(删除)1.4.1语法1.4.2含义 二…

Aop编程之动态代理

1、Java代理介绍 Java中的代理方式包括静态代理和动态代理。 静态代理在编译期间就确定了代理对象&#xff0c;动态代理是在运行期间动态生成代理对象。动态代理包括cglib动态代理和jdk动态代理&#xff0c;在目标对象有接口的情况下&#xff0c;可以使用jdk动态代理或者cglib…

PyTorch项目源码学习(2)——Tensor代码结构初步学习

PyTorch版本&#xff1a;1.10.0 Tensor Tensor是Pytorch项目较为重要的一部分&#xff0c;其中的主要功能如存储&#xff0c;运算由C和CUDA实现&#xff0c;本文主要从前端开始探索学习Tensor的代码结构。 结构探索 PyTorch前端位于torch目录下&#xff0c;从_tensor.py可以…

手持终端PDA定制厂家_5G安卓手持机设备/条形码扫描手持机PDA

手持终端PDA是一种功能强大的手持终端设备&#xff0c;具备一维码和二维码扫描功能&#xff0c;广泛应用于门票管理、零售、智能巡检、仓储物资管理、金融、快递等领域。 这款手持终端基于MT6877方案&#xff0c;搭载八核处理器(2xCortex-A78 2.4GHz 6xCortex-A55 2.0GHz)&…

【机器学习前置知识】狄利克雷分布

在阅读本文前&#xff0c;建议先食用以下几篇文章以能更好地理解狄利克雷分布&#xff1a; 二项分布 Beta分布 多项分布 共轭分布 狄利克雷分布 狄利克雷分布(Dirichlet distribution)是Beta分布的扩展&#xff0c;把Beta分布从二元扩展到多元形式就是狄利克雷分布&#…

【PixPin】比Snipaste、QQ的截图长图和动图还好用的截图工具

1.下载地址—— 下载地址 2.下载压缩包 双击exe文件运行 按默认的来 中文安装 选择安装路径 下一步&#xff0c;安装 安装完成&#xff0c;可以自己设置快捷键

使用Django框架自带的Form表单完成简单的用户登录注册

如果不知道怎么配置Django环境以及如何连接数据库请点击我的上一篇博客&#xff1a; 使用pycharm初始化Django框架并连接Sql Server 文章目录 1.Django默认生成的数据表2.用户登录2.1创建登录页面2.2视图处理登录请求2.3配置访问路径 3.用户注册3.1创建用户表单3.2创建注册模版…

VScode代码格式化

Vscode代码格式化 有时候总是想,为什么我的代码格式化完后为什么这么挤,而且不想让代码在格式化后换行,他总是自动换行,所以我去网上查了相关资料 第一步,搜索插件ESLint并安装,安装完成后你就可以进行格式化了 第二步,设置中选择settings,搜索Tab size,根据一下图片更改 第…

全志T113开发板Qt远程调试

1引言 通常情况下工程师在调试Qt程序时&#xff0c;需要频繁制作镜像烧录到核心板来测试Qt程序是否完善&#xff0c;这样的操作既费时又费力。这时我们可以通过QtCreator设备功能&#xff0c;定义设备后&#xff0c;在x86_64虚拟机上交叉编译qt程序&#xff0c;将程序远程部署到…

ubuntu 18.04网络问题

ubuntu 18.04网络问题汇总 准备工作一、有线网卡不可用二、无法访问外网 准备工作 安装好系统之后&#xff0c;检查gcc和make是否已经安装 $ which gcc /usr/bin/gcc $ which make /usr/bin/make如果未安装&#xff0c;则安装gcc和make $ apt install gcc $ apt install mak…

Golang协程池ants库的学习、使用及源码阅读,协程池与GMP模型关系的理解

前言 在工作时遇到了一个需要使用ants协程池的地方&#xff0c;因此顺带来学习一下他的原理。 协程池 Golang的资源还是偏少一些…因此先简单的参考学习了一下线程池。 类似于Java中的线程池&#xff0c;协程池也是为了减少协程频繁创建、销毁所带来资源消耗的问题。按默认每…

【我想开发一个小程序,大概需要多少钱?】

小程序开发为什么报价差距很大&#xff1f;主要是因为小程序的实现方法和功能模型不同。 小程序的实现方法&#xff1a; 实现方法主要分为SAAS小程序、定制小程序和第三方平台小程序。不同的实现方法价格都是不一样的&#xff0c;大概的区间如下&#xff1a; SAAS小程序和第三…

ChatGPT+Python近红外光谱数据分析及机器学习与深度学习建模进阶应用

目录 第一章 ChatGPT4入门基础 第二章 ChatGPT4 提示词使用方法与技巧 第三章 ChatGPT4助力信息检索与总结分析 第四章 ChatGPT4助力论文写作与投稿 第五章 ChatGPT4助力Python入门基础 第六章 ChatGPT4助力近红外光谱数据预处理 第七章 ChatGPT4助力多元线性回归近红外…