当前位置: 首页 > news >正文

备战蓝桥day-7(递归回溯)

1、递归+回溯算法

大致思想:从开始若满足条件则一直往后递归下去,直到条件不符或者已完成任务回溯到前一个状态,用来找到所有符合条件的情况。

例题:

题目背景

猪猪 Hanke 得到了一只鸡。

题目描述

猪猪 Hanke 特别喜欢吃烤鸡(本是同畜牲,相煎何太急!)Hanke 吃鸡很特别,为什么特别呢?因为他有 10 种配料(芥末、孜然等),每种配料可以放 1 到 3 克,任意烤鸡的美味程度为所有配料质量之和。

现在, Hanke 想要知道,如果给你一个美味程度 n ,请输出这 10 种配料的所有搭配方案。

输入格式

一个正整数 n,表示美味程度。

输出格式

第一行,方案总数。

第二行至结束,10 个数,表示每种配料所放的质量,按字典序排列。

如果没有符合要求的方法,就只要在第一行输出一个 0。

输入输出样例

输入 #1复制

11

输出 #1复制

10
1 1 1 1 1 1 1 1 1 2 
1 1 1 1 1 1 1 1 2 1 
1 1 1 1 1 1 1 2 1 1 
1 1 1 1 1 1 2 1 1 1 
1 1 1 1 1 2 1 1 1 1 
1 1 1 1 2 1 1 1 1 1 
1 1 1 2 1 1 1 1 1 1 
1 1 2 1 1 1 1 1 1 1 
1 2 1 1 1 1 1 1 1 1 
2 1 1 1 1 1 1 1 1 1 

说明/提示

对于 100% 的数据,n≤5000。

#include<bits/stdc++.h>
using namespace std;
vector<vector<int>> res;  //存储所有组合
void backtrack(int step,int current_sum,vector<int>& path,int n){
	if(step==10){
		if(current_sum==n)
		res.push_back(path);  //若十种配料都齐了且总量为n则加入组合,否则返回回溯 
		return ;
	}
	for(int i=1;i<=3;i++){
		int remaining=10-step-1;
		int min_required=remaining*1;
		int max_required=remaining*3;
		int new_sum=current_sum+i;
		//当前i无法形成有效组合,剪枝 
		if(new_sum+min_required>n) continue;
		if(new_sum+max_required<n) continue;
		path.push_back(i); //可以加入当前i,到下一种配料 
		backtrack(step+1,new_sum,path,n);
		path.pop_back(); //回溯到前一个状态  
	} 
} 
int main(){
	int n;
	cin>>n;
	if(n<10||n>30){
		cout<<0<<endl;
		return 0;
	} 
	vector<int> path;
	backtrack(0,0,path,n);
	cout<<res.size()<<endl;
	for(auto& v:res){   //增强for循环,自推导类型auto 
		for(int i=0;i<10;i++){
			cout<<v[i]<<" ";
		}
		cout<<endl;
	}
	return 0;
}

2、最大公约数与数字查找

题目描述

将 1,2,…,9 共 9 个数分成三组,分别组成三个三位数,且使这三个三位数的比例是 A:B:C,试求出所有满足条件的三个三位数,若无解,输出 No!!!

//感谢黄小U饮品完善题意

输入格式

三个数,A,B,C。

输出格式

若干行,每行 3 个数字。按照每行第一个数字升序排列。

输入输出样例

输入 #1复制

1 2 3

输出 #1复制

192 384 576
219 438 657
273 546 819
327 654 981

说明/提示

保证 A<B<C。


upd 2022.8.3:新增加二组 Hack 数据。

大致思路:首先对输入的比例进行判断,如果有0出现是没有意义的直接输出No,然后将比例化为最简整数比,以便找出所有的组合,这里用到了找最大公约数函数gcd,即循环取余直至为0。然后要生成1~9组成的三个数形成对应比例,即a*k,b*k,c*k三个数。对k的取值进行限定,然后对生成的数进行逐位判断即可,数中不包含0,无重复数字,包含了0~9,这里用到了位掩码,即used |=(1<<d);//表示将第d位数字设置为1;used&(1<<d)//判断第d位是否为1.代码如下:

#include<bits/stdc++.h>
using namespace std; 
//求最大公约数,循环取余 
int gcd(int a,int b){
	while(b){
		int temp=a%b;
		a=b;
		b=temp;
	}
	return a;
}
//检查数字是1~9 
bool check(int x,int y,int z){
	int used=0; //用位掩码来表示各个位置的状态 
	int digits[9];
	digits[0]=x/100;  //百位 
	digits[1]=(x/10)%10; //十位 
	digits[2]=x%10; //个位 
    digits[3]=y/100;
	digits[4]=(y/10)%10;
	digits[5]=y%10;
	digits[6]=z/100;
    digits[7]=(z/10)%10;
	digits[8]=z%10;
	//数字不为0且不重复 
	for(int i=0;i<9;i++){
		int d=digits[i];
		if(d==0||used&(1<<d))//检查第d位是否出现过 
		return false;
		used |=(1<<d); //将第d位设置为1 
	}
	//确保数字包含1~9 
	return used==0b1111111110; 
} 
int main(){
	int A,B,C;
	cin>>A>>B>>C;
	if(A==0||B==0||C==0){
		cout<<"No!!!"<<endl;
		return 0;
	} 
	int g=gcd(gcd(A,B),C);
	int a=A/g,b=B/g,c=C/g;
	int low=100/a;
	int high=999/c;
	vector<vector<int>> result; 
	for(int k=low;k<=high;k++){
		int x=a*k,y=b*k,z=c*k;
		if(check(x,y,z))
		result.push_back({x,y,z});
	}
	if(result.empty()){
		cout<<"No!!!"<<endl;
	}else{
		for(const auto &ele:result){
			cout<<ele[0]<<" "<<ele[1]<<" "<<ele[2]<<endl;
		}
	} 
  return 0;
} 

3、矩阵旋转

方阵顺时针旋转90度:先把方阵转置,即将对角线两边对称的元素交换位置,然后再将每一行反转reverse,逆时针则先反转每一行再将对角线两边对称的元素交换位置。

例题:

题目描述

Scarlet 最近学会了一个数组魔法,她会在 n×n 二维数组上将一个奇数阶方阵按照顺时针或者逆时针旋转 90∘。

首先,Scarlet 会把 1 到 n2 的正整数按照从左往右,从上至下的顺序填入初始的二维数组中,然后她会施放一些简易的魔法。

Scarlet 既不会什么分块特技,也不会什么 Splay 套 Splay,她现在提供给你她的魔法执行顺序,想让你来告诉她魔法按次执行完毕后的二维数组。

输入格式

第一行两个整数 n,m,表示方阵大小和魔法施放次数。

接下来 m 行,每行 4 个整数 x,y,r,z,表示在这次魔法中,Scarlet 会把以第 x 行第 y 列为中心的 2r+1 阶矩阵按照某种时针方向旋转,其中 z=0 表示顺时针,z=1 表示逆时针。

输出格式

输出 n 行,每行 n 个用空格隔开的数,表示最终所得的矩阵

输入输出样例

输入 #1复制

5 4
2 2 1 0
3 3 1 1
4 4 1 0
3 3 2 1

输出 #1复制

5 10 3 18 15
4 19 8 17 20
1 14 23 24 25
6 9 2 7 22
11 12 13 16 21

说明/提示

对于50%的数据,满足 r=1

对于100%的数据 1≤n,m≤500,满足 1≤x−r≤x+r≤n,1≤y−r≤y+r≤n。

#include<bits/stdc++.h>
using namespace std;
//小矩阵的左上角坐标为x,y,k阶方阵
void spin(vector<vector<int>>& matrix,int x,int y,int k,int z){
	vector<vector<int>> subMatrix(k,vector<int>(k));
	for(int i=0;i<k;i++){
		for(int j=0;j<k;j++)
		subMatrix[i][j]=matrix[x+i][y+j];
	}
	if(z==0){
		//顺时针旋转90度,先转置,按对角线交换元素,再反转每一行 
		for(int i=0;i<k;i++){
			for(int j=i;j<k;j++){
				swap(subMatrix[i][j],subMatrix[j][i]);
			}
		}
		//反转每一行元素 
		for(int i=0;i<k;i++){
			reverse(subMatrix[i].begin(),subMatrix[i].end());
		}
		//把旋转后的元素放回去 
		for(int i=0;i<k;i++){
			for(int j=0;j<k;j++){
				matrix[x+i][y+j]=subMatrix[i][j];
			}
		}
	}else if(z==1){
		//逆时针旋转90度,先反转行,在进行转置 
		for(int i=0;i<k;i++){
			reverse(subMatrix[i].begin(),subMatrix[i].end());
		}
		for(int i=0;i<k;i++){
			for(int j=i;j<k;j++){
				swap(subMatrix[i][j],subMatrix[j][i]);
			}
		} 
		for(int i=0;i<k;i++){
			for(int j=0;j<k;j++){
				matrix[x+i][y+j]=subMatrix[i][j];
			}
		}
	}
}
int main(){
	int n,m;
	cin>>n>>m;
	vector<vector<int>> matrix(n,vector<int>(n)); 
	int ans=1;
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			matrix[i][j]=ans;
			ans++;
		}
	}
	int x,y,r,z;
	for(int i=0;i<m;i++){
		cin>>x>>y>>r>>z;
		spin(matrix,x-1-r,y-1-r,2*r+1,z);
	}
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++)
		cout<<matrix[i][j]<<" ";
	    cout<<endl;
	}
        return 0;
} 

相关文章:

  • PP-PLL:基于概率传播的部分标签学习
  • Python第六章13:集合(set)的定义和操作
  • 【euclid】21 3D包围盒模块(box3d.rs)
  • 【Python Cookbook】字符串和文本(二)
  • 【鸿蒙开发】第五十一章 Camera Kit(相机服务)
  • pagehelper 分页插件使用说明
  • 程序化广告行业(33/89):深入了解OTT、OTV及多样广告形式
  • 文字也能生成视频?【蓝耘实践】:通义万相2.1文生视频
  • SPPAS安装及问题汇总
  • 生成对抗网络(GAN)模型的详细介绍
  • 数据结构与算法-图论-强连通分量(tarjan算法)
  • 开个坑记录一下树莓派4B部署yolo的一些问题
  • C++手撕共享指针、多线程交替、LRU缓存
  • 6.milvus搜索search
  • 程序化广告行业(31/89):人群分类与广告投放策略全解析
  • 搜广推校招面经五十八
  • CAN基础知识学习二
  • Rust Web 开发新选择:探索 Hyperlane 轻量级 HTTP 服务器框架
  • 如何运用口语APP自学掌握英语,做到流畅交流
  • springMVC中视图机制简述
  • bootstrap网站模板下载/苏州优化网站公司
  • wordpress文学模版/短视频seo公司
  • 胶南网/滨州seo排名
  • 上海做网站吧/万网官网域名查询
  • 专家称第二波疫情风暴会很低/北京seo包年
  • 门户网站建设哪家好/seo深圳培训班