【C++】C++11语法 ~ 可变参数模板

news2024/11/18 17:50:14

🌈欢迎来到C++专栏~可变参数模板


  • (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是Scort
  • 目前状态:大三非科班啃C++中
  • 🌍博客主页:张小姐的猫~江湖背景
  • 快上车🚘,握好方向盘跟我有一起打天下嘞!
  • 送给自己的一句鸡汤🤔:
  • 🔥真正的大师永远怀着一颗学徒的心
  • 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏
  • 🎉🎉欢迎持续关注!
    在这里插入图片描述

请添加图片描述

文章目录

  • 🌈欢迎来到C++专栏~可变参数模板
    • 一. 类的新功能
      • 🥑默认成员函数
      • 🥑类成员变量初始化
      • 🥑强制生成默认函数的关键字`default`
      • 🥑禁止生成默认函数的关键字delete
    • 二. 可变模板参数
      • 💦模板定义
      • 💦参数包的展开
        • 😎递归函数方式展开
        • 😎逗号表达式展开
    • 三. emplace
      • ✨使用方法
      • ✨工作原理
      • ✨意义
  • 📢写在最后

请添加图片描述

一. 类的新功能

🥑默认成员函数

C++11之后,有八个默认成员函数

在C++11之前,一个类中有如下六个默认成员函数:

  • 构造函数
  • 析构函数
  • 拷贝构造函数
  • 拷贝赋值函数
  • 取地址重载函数
  • const取地址重载函数

其中前四个成员函数最重要,后面两个成员函数一般不会用到,这里“默认”的意思就是你不写编译器会自动生成。在C++11标准中又增加了两个默认成员函数,分别是移动构造函数和移动赋值重载函数

✨默认移动构造和移动赋值的生成条件

  • 默认移动构造生成条件:没有自己实现移动构造函数,并且没有自己实现析构函数、拷贝构造函数和拷贝赋值函数的任意一个
  • 移动赋值重载函数的生成条件:没有自己实现移动赋值重载函数,并且没有自己实现析构函数、拷贝构造函数和拷贝赋值函数

😎特别注意: 如果我们自己实现了移动构造或者移动赋值,就算没有实现拷贝构造和拷贝赋值,编译器也不会生成默认的拷贝构造和拷贝赋值

默认生成的移动构造和移动赋值会做什么?

  • 对于内置类型的成员会完成值拷贝(浅拷贝),对于自定义类型的成员,如果该成员实现了移动构造/移动赋值就调用它的移动构造/移动赋值,否则就调用它的拷贝构造

对此我们展开验证,这里需要模拟实现一个简化版的string类,类当中只编写了几个我们需要用到的成员函数。

代码如下:

namespace ljj
{
	class string
	{
	public:
		typedef char* iterator;
		iterator begin()
		{
			return _str; //返回字符串中第一个字符的地址
		}
		iterator end()
		{
			return _str + _size; //返回字符串中最后一个字符的后一个字符的地址
		}
		//构造函数
		string(const char* str = "")
		{
			_size = strlen(str); //初始时,字符串大小设置为字符串长度
			_capacity = _size; //初始时,字符串容量设置为字符串长度
			_str = new char[_capacity + 1]; //为存储字符串开辟空间(多开一个用于存放'\0')
			strcpy(_str, str); //将C字符串拷贝到已开好的空间
		}
		//交换两个对象的数据
		void swap(string& s)
		{
			//调用库里的swap
			::swap(_str, s._str); //交换两个对象的C字符串
			::swap(_size, s._size); //交换两个对象的大小
			::swap(_capacity, s._capacity); //交换两个对象的容量
		}
		//拷贝构造函数(现代写法)
		string(const string& s)
			:_str(nullptr)
			, _size(0)
			, _capacity(0)
		{
			cout << "string(const string& s) -- 深拷贝" << endl;

			string tmp(s._str); //调用构造函数,构造出一个C字符串为s._str的对象
			swap(tmp); //交换这两个对象
		}

		//移动构造
		string(string&& s)//右值引用
			:_str(nullptr)
			, _size(0)
			, _capacity(0)
		{
			cout << "string(string&& s) -- 资源转移" << endl;

			swap(s); //资源互换
		}

		//赋值运算符重载(现代写法)
		string& operator=(const string& s)
		{
			cout << "string& operator=(const string& s) -- 深拷贝" << endl;

			string tmp(s); //用s拷贝构造出对象tmp
			swap(tmp); //交换这两个对象
			return *this; //返回左值(支持连续赋值)
		}

		//移动赋值
		string& operator=(string&& s)
		{
			cout << "string& operator=(const string&& s) -- 移动赋值" << endl;
			swap(s);

			return *this; //返回左值(支持连续赋值)
		}

		//析构函数
		~string()
		{
			delete[] _str;  //释放_str指向的空间
			_str = nullptr; //及时置空,防止非法访问
			_size = 0;      //大小置0
			_capacity = 0;  //容量置0
		}
		//[]运算符重载
		char& operator[](size_t i)
		{
			assert(i < _size); //检测下标的合法性
			return _str[i]; //返回对应字符
		}
		//改变容量,大小不变
		void reserve(size_t n)
		{
			if (n > _capacity) //当n大于对象当前容量时才需执行操作
			{
				char* tmp = new char[n + 1]; //多开一个空间用于存放'\0'
				strncpy(tmp, _str, _size + 1); //将对象原本的C字符串拷贝过来(包括'\0')
				delete[] _str; //释放对象原本的空间
				_str = tmp; //将新开辟的空间交给_str
				_capacity = n; //容量跟着改变
			}
		}
		//尾插字符
		void push_back(char ch)
		{
			if (_size == _capacity) //判断是否需要增容
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2); //将容量扩大为原来的两倍
			}
			_str[_size] = ch; //将字符尾插到字符串
			_str[_size + 1] = '\0'; //字符串后面放上'\0'
			_size++; //字符串的大小加一
		}
		//+=运算符重载
		string& operator+=(char ch)
		{
			push_back(ch); //尾插字符串
			return *this; //返回左值(支持连续+=)
		}
		//返回C类型的字符串
		const char* c_str()const
		{
			return _str;
		}
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	};
}

再编写一个简单的Person类,Person类中的成员name的类型就是我们模拟实现的string类

class Person
{
public:
	//构造函数
	Person(const char* name = "", int age = 0)
		:_name(name)
		, _age(age)
	{}
	//拷贝构造函数
	Person(const Person& p)
		:_name(p._name)
		, _age(p._age)
	{}
	//拷贝赋值函数
	Person& operator=(const Person& p)
	{
		if (this != &p)
		{
			_name = p._name;
			_age = p._age;
		}
		return *this;
	}
	//析构函数
	~Person()
	{}
private:
	cl::string _name; //姓名
	int _age;         //年龄
};

因为Person类中实现了拷贝构造、拷贝赋值和析构函数等,所以不会默认生成移动构造和移动赋值

int main()
{
	Person s1("张三", 7);
	Person s2 = s1;//拷贝构造
	Person s3 = std::move(s1);//移动构造(没有移动构造,就会调用拷贝构造)
	return 0;
}

在这里插入图片描述

ps:由于VS2013没有完全支持C++11,因此上述代码无法在VS2013当中验证,需要使用更新一点的编译器进行验证,比如VS2019

🥑类成员变量初始化

默认生成的构造函数,对于自定义类型的成员会调用其构造函数进行初始化,但并不会对内置类型的成员进行处理。于是C++11支持非静态成员变量在声明时进行初始化赋值,默认生成的构造函数会使用这些缺省值对成员进行初始化

class Person
{
public:
	//...
private:
	//非静态成员变量,可以在成员声明时给缺省值
	ljj::string _name = "张三"; //姓名
	int _age = 20;             //年龄
	static int _n; //静态成员变量不能给缺省值
};

🥑强制生成默认函数的关键字default

C++11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数,但是因为一些原因这个函数没有默认生成。比如:我们提供了拷贝构造,就不会生成移动构造了,那么我们可以使用default关键字显示指定移动构造生成

下面函数实现了拷贝构造

class Person
{
public:
	//拷贝构造函数
	Person(const Person& p)
		:_name(p._name)
		, _age(p._age)
	{}
private:
	cl::string _name; //姓名
	int _age;         //年龄
};

这样编译器就无法生成默认的构造函数了,因为默认构造函数生成的条件是没有编写任意类型的构造函数包括拷贝构造函数

这时我们就可以使用default关键字强制生成默认的构造函数

class Person
{
public:
	Person() = default; //强制生成默认构造函数

	//拷贝构造函数
	Person(const Person& p)
		:_name(p._name)
		, _age(p._age)
	{}
private:
	cl::string _name; //姓名
	int _age;         //年龄
};

主要使用场景:用于构造函数,因为如果我们实现了拷贝构造(也算构造),就不会默认生成构造函数了,需要强制生成

🥑禁止生成默认函数的关键字delete

当我们想要限制某些默认函数生成

  • C++98中,可以将该函数设置成私有,并且只用声明不用定义,这样当外部调用该函数时就会报错。
  • C++11中,可以在该函数声明后面加上=delete,表示让编译器不生成该函数的默认版本,我们将=delete修饰的函数称为删除函数
class Person
{
public:
	//构造函数
	Person(const char* name = "", int age = 0)
		:_name(name)
		, _age(age)
	{}
	//不想要Person对象拷贝
	Person(const Person& p) = delete;
private:
	ljj::string _name; //姓名
	int _age;         //年龄
};

int main()
{
	Person s1("张三", 7);
	Person s2 = s1;//拷贝构造
	return 0;
}

来道题目:要求delete关键字实现,一个类只能在堆上创建对象

class HeapOnly
{
public:
	HeapOnly()
	{
		_str = new char[10];
	}

	~HeapOnly() = delete;

	void Destroy()
	{
		delete[] _str;//删除开创的空间
		free(this);//删除ptr指针
	}

private:
	char* _str;
};

int main()
{
	HeapOnly* ptr = new HeapOnly;
	ptr->Destroy();
	return 0;
}

如果是构造时,对象有数据,则要我们手动实现一个类似析构函数的函数,析构要注意两块空间哦:ptr指针和new的空间都要释放了

二. 可变模板参数

C++11 新增一员大将就是可变参数模板,他可以允许可变参数的函数模板和类模板来作为参数,使得参数高度泛化

💦模板定义

函数的可变参数模板定义方式如下:

template<class …Args>
void ShowList(Args… args)
{
  //函数体
}
  • Args是一个模板参数包,args是一个函数形参参数包
    声明一个参数包Args…args,这个参数包中可以包含0到任意个模板参数

模板参数包 Args 和函数形参参数包 args 的名字可以任意指定,并不是说必须叫做 Args 和 args

int main()
{
	//函数传参就可以传多个不同类型参数了
	string str("hello");
	ShowList();
	ShowList(1);
	ShowList(1, 'A');
	ShowList(1, 'A', str);
	return 0;
}

也可以通过sizeof算出参数包中参数的个数:...是在外面的

template<class ...Args>
void ShowList(Args... args)
{
	cout << sizeof...(args) << endl; //获取参数包中参数的个数
}

此时最大的难点来了,就是怎么样直接获取参数包中的每个参数?

  • 语法并不支持使用 args[i] 的方式来获取参数包中的参数,只能通过展开参数包的方式来获取,这是使用可变参数模板的一个主要特点

下面是错误示范:(语法不支持!)

template<class ...Args>
void ShowList(Args... args)
{
	cout << sizeof...(args) << endl;

	//错误示例:
	for (int i = 0; i < sizeof...(args); i++)
	{
		cout << args[i] << " "; //打印参数包中的每个参数
	}
	cout << endl;
}

💦参数包的展开

😎递归函数方式展开

该方法大概分为三步:

  • 给函数模板增加一个模板参数,从接收的参数包中把第一个参数分离出来
  • 在函数模板中递归调用该函数模板,调用时传入剩下的参数包
  • 直到递归到参数包为空,退出递归
//可变参数的函数模板 
template<class T, class ...Args>
void ShowList(const T& val, Args... args)
{
	cout << val << " ";//打印分离出的第一个参数
	ShowList(args...);//继续递归调用
}

//递归至空,终止函数
void ShowList()
{
	cout << endl;
}

int main()
{
	string str("hello");
	ShowList(1, 'A', str);
	return 0;
}

在这里插入图片描述

那如果我们不使用递归调用,该怎么样写呢?

😎逗号表达式展开

逗号表达式规则是会从左到右依次计算各个表达式,并将最后一个表达式的值作为返回值返回,我们将最后一个表达式设为整型值,确保最后返回的是一个整型

将处理参数个数的动作封装成一个函数,将该函数作为逗号表达式的第一个表达式

template <class T>
void PrintArg(const T& x)
{
	cout << x << " ";
}

template <class ...Args>
void ShowList(Args... args)
{
	int a[] = { (PrintArg(args), 0)... };//开创输入参数个整数类型的数组
}

我们要的是打印出参数包中的各个参数,因此处理函数当中要做的就是将传入的参数进行打印即可

ps:可变参数的省略号...需要加在逗号表达式外面,表示需要先将逗号表达式展开,如果直接加在 args 后面,那么参数包将会被展开后全部传入 PrintArg,会展开成 {(PrintArg(arg1), 0), (PrintArg(arg2), 0), (PrintArg(arg3), 0), etc…}

在这里插入图片描述

当然我们不使用逗号表达式也是可以的,这里的问题是初始化整型数组时必须用整数,那我们可以将处理函数的返回值设为整型,然后用这个返回值去初始化整型数组也是可以的:

void ShowList()
{
	cout << endl;
}
//处理函数
template<class T>
int PrintArg(const T& t)//返回值为int类型
{
	cout << t << " ";
	return 0;
}
//展开函数
template<class ...Args>
void ShowList(Args... args)
{
	int arr[] = { PrintArg(args)... }; //列表初始化
	cout << endl;
}

三. emplace

C++11 给 STL 容器增加 emplace 的插入接口,比如 list 容器的 push_front、push_back 和insert 函数,都有了对应的 emplace_front、emplace_back 和 emplace 函数:

在这里插入图片描述

这些emplace版本的插入接口支持模板的可变参数,比如vector容器的emplac函数的声明如下:

在这里插入图片描述

✨使用方法

调用 push_back 插入元素时,可以传入左值对象或右值对象,也可以使用列表进行初始化;调用emplace_back 插入元素时,也可以传入左值对象或右值对象,但不可以使用列表进行初始化

emplace系列接口最大的特点就是,插入元素可传入用于构造元素的参数包

int main()
{
	//对于整形:没有区别
	vector<int> v;
	v.push_back(1);
	v.emplace_back(2);

	//对于pair类型数据
	vector<pair<std::string, int>> v1;
	v1.push_back(make_pair("sort", 1));
	v1.emplace_back("sort", 1);

	return 0;
}

那么emplace会比push_back更加高效吗?不一定!

✨工作原理

emplace 接口先通过空间配置器为新结点获取一块内存空间,注意这里只会开辟空间,不会自动调用构造函数对这块空间进行初始化

  • 调用 allocator_traits::construct 函数对这块空间进行初始化,调用该函数会传入这块空间的地址和用户传入的参数,注意要完美转发
  • 在 allocator_traits::construct 中会使用定位 new 表达式,显示调用构造函数对这块空间进行初始化,调用构造函数时会传入用户传入的参数,这里同样需要完美转发

✨意义

emplace 接口的可变参数模板类型都是万能引用,因此既可以接收左值,也可以接收右值,还可以接收参数包

  • 调用 emplace 接口时传入的是参数包,就可以直接调用函数进行插入,并最终使用定位 new 表达式调用构造函数对空间进行初始化时,匹配到构造函数
  • 调用 emplace 接口时传入的是左值or右值,首先需要先在此之前调用构造函数实例化出一个对象,最后使用定位 new 表达式调用构造函数对空间进行初始化时,会匹配到拷贝构造函数or拷贝构造

总的来说:如果传入参数包,只需要调用构造函数

在这里插入图片描述

emplace 最大特点就是支持传入参数包,用这些参数包直接构造出对象,这样就能减少一次拷贝,这就是为什么有人说 emplace 系列接口更高效的原因

emplace 真正高效的情况是传入参数包的时候, 直接通过参数包构造出对象,避免了中途的一次拷贝 直接通过参数包构造出对象,避免了中途的一次拷贝

举例演示:

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "构造函数" << endl;
	}

	Date(const Date& d)
		:_year(d._year)
		, _month(d._month)
		, _day(d._day)
	{
		cout << "拷贝构造" << endl;
	}

	Date& operator=(const Date& d)
	{
		cout << "赋值重载" << endl;
		return *this;
	}

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	list<Date> lt1;

	lt1.push_back(Date(2023, 2, 3));
	cout << endl;
	lt1.emplace_back(2023, 2, 3);
}

在这里插入图片描述

所以验证了emplace_back是比push_back要少一次拷贝构造

📢写在最后

请添加图片描述

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

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

相关文章

2月3日第壹简报,星期五,农历正月十三

2月3日第壹简报&#xff0c;星期五&#xff0c;农历正月十三坚持阅读&#xff0c;静待花开1. 香港&#xff1a;将向世界各地旅客派发50万张免费机票&#xff0c;3月1日起派发&#xff0c;为期6个月&#xff0c;率先向东南亚地区送出。2. 我国新增18处国际重要湿地&#xff0c;湿…

聚观早报|网易开放暴雪游戏退款申请通道;鱼跃医疗回应被罚270万

今日要闻&#xff1a;网易开放暴雪游戏退款申请通道&#xff1b;谷歌 ChatGPT 竞品搜索设计将迎来大改&#xff1b;“鱼跃医疗”回应被罚270万元&#xff1b;大众考虑在加拿大建设新的电池工厂&#xff1b;微软将把ChatGPT整合到必应搜索中网易开放暴雪游戏退款申请通道 2 月 1…

力扣刷题|654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树

LeetCode 654.最大二叉树 题目链接&#x1f517; LeetCode 654.最大二叉树 思路 最大二叉树的构建过程如下&#xff1a; 构造树一般采用的是前序遍历&#xff0c;因为先构造中间节点&#xff0c;然后递归构造左子树和右子树。 class Solution {public TreeNode constructM…

构造http请求的几种方式(附源码)

文章目录前言一、form表单构造http请求二、ajax构造http请求三、Java socket构造http请求总结前言 博主个人社区&#xff1a;开发与算法学习社区 博主个人主页&#xff1a;Killing Vibe的博客 欢迎大家加入&#xff0c;一起交流学习~~ 一、form表单构造http请求 form (表单) 是…

SSH基础知识(一)

SSH基础知识SSH对称加密非对称加密如何生成秘钥如何管理秘钥不同版本ssh命令安装ssh启动ssh服务登录ssh退出ssh登录远程登录执行命令ssh参数端口转发本地转发远程转发动态转发最近有用到SFTP协议完成一些功能开发&#xff0c;这玩意和FTP比较像&#xff0c;当时以为是升级版&am…

FPGA和CPLD芯片选型介绍(二)

FPGA器件选型&#xff08;以Xilinx和Altera为例&#xff09;器件选型是件很严肃的事情&#xff0c;既要考虑性能又要兼顾成本&#xff0c;还要考虑长期供货的稳定性&#xff0c;因此很考验工程师的知识广度储备。一般而言&#xff0c;FPGA&#xff08;CPLD&#xff09;需要分三…

3、Maven——Maven创建java web工程,Maven search插件

目录 一、Maven创建java web工程 二、Maven创建java web项目的结构 1、添加项目目录 2、web.xml配置处理报错 三、IDEA更改XML版本 一、Maven创建java web工程 创建Empty Project空工程&#xff1b;右击Empty Project工程--->New--->Module--->Maven Archetype N…

Linux环境下安装软件合集【2】

Linux环境下安装软件合集【2】 Linux环境下安装软件合集【1】 1 安装tomcat 1.1 安装启动tomcat 下载tomcat压缩包 通过wget方式 wget --no-check-certificate https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.70/bin/apache-tomcat-9.0.70.tar.gz直接官网下载压缩包&…

23k入职腾讯测试岗那天,我哭了,这5个月付出的一切总算没有白费~

先说一下自己的个人情况&#xff0c;计算机专业&#xff0c;16年普通二本学校毕业&#xff0c;经历过一些失败的工作经历后&#xff0c;经推荐就进入了华为的测试岗&#xff0c;进去才知道是接了个外包项目&#xff0c;不太稳定的样子&#xff0c;可是刚毕业谁知道什么外包不外…

基于SSH框架的学生成绩管理系统源码+数据库,Struts2、Spring与Hibernate整合应用,实验报告

Struts2、Spring与Hibernate整合应用&#xff1a;基于SSH框架的学生成绩管理系统 最近一个实验课程&#xff0c;需要做一个基于SSH框架的学生成绩管理系统。就简简单单做了一下…… 1.1 实验要求&#xff1a; &#xff08;1&#xff09; 整合Struts2、Spring和Hibernate框架 …

​箭头函数和普通函数的区别​

一.外形不同&#xff1a;箭头函数使用箭头定义&#xff0c;普通函数中没有 代码实例如下&#xff1a; // 普通函数 function func(){// code } // 箭头函数 let func()>{// code } 二.箭头函数都是匿名函数 普通函数可以有匿名函数&#xff0c;也可以有具体名函数&#xf…

框架高级课程系列之Redis6笔记

文章目录前言NoSQL数据库简介技术发展NoSQL数据库NoSQL适用场景NoSQL不适用场景Redis概述安装配合关系型数据库做高速缓存多样的数据结构存储持久化数据Redis 安装准备工作&#xff1a;下载安装最新版的gcc编译器启动 Redis方式Redis 关闭方式Redis介绍相关知识常用五大数据类型…

如何利用python机器学习解决空间模拟与时间预测问题及经典案例分析

目录 专题一 机器学习原理与概述 专题二 Python编译工具组合安装教程 专题三 掌握Python语法及常见科学计算方法 专题四 机器学习数据清洗 专题五 机器学习与深度学习方法 专题六 机器学习空间模拟实践操作 专题七 机器学习时间预测实践操作 更多推荐 了解机器学习的发…

Web服务器TomCat快速入门(从安装到部署)

文章目录什么是Web服务器&#xff1f;相关概念基本使用下载安装卸载启动关闭配置部署&#x1f4c2;橙子精品文章学习推荐什么是Web服务器&#xff1f; Web 服务器是一个应用程序&#xff0c;对 HTTP 协议的操作进行封装&#xff0c;使得程序员不必直接对协议进行操作&#xff…

【Linux 系统运维基础】Linux命令大全

Linux 命令大全立志列举出Linux中常用的所有命令(有很多命令不使用的话&#xff0c;很快会忘记哦)。 1. cd 目录前进/ 后缀 cd /表示跳转到根目录下&#xff0c;无论是哪个目录下&#xff0c;执行此命令后一定会跳转到根目录下。 cd ~ 表示跳转到主目录下。 cd . 表示跳转还…

【5.2】Nacos注册中心--服务多级存储模型

【【5.2】Nacos注册中心--服务多级存储模型1 Nacos服务多级存储模型2 服务跨集群调用问题3 配置集群属性4 总结1 Nacos服务多级存储模型 之前有服务的概念&#xff1a; 例如&#xff1a;提供用户查询的use-service和提供订单查询的order-service&#xff0c;它们都叫服务。 我…

Linux安装配置JDK安装运行Tomcat

Linux软件主流安装方式: tar:解压安装(前提将安装包下载下来) 安装包格式:tar,tar.gz,tar.bz 安装解压包命令: tar -zxvf 包名xxx rpm:直接安装,需要将安装包下载下来(好比双击window里的.exe文件) 安装包格式:rpm 安装命令:rpm -ivh 软件路径 卸载命令:rpm -e 软件包全名 y…

【GPLT 二阶题目集】L2-014 列车调度

火车站的列车调度铁轨的结构如下图所示。 两端分别是一条入口&#xff08;Entrance&#xff09;轨道和一条出口&#xff08;Exit&#xff09;轨道&#xff0c;它们之间有N条平行的轨道。每趟列车从入口可以选择任意一条轨道进入&#xff0c;最后从出口离开。在图中有9趟列车&am…

(蓝桥杯 刷题全集)【备战(蓝桥杯)算法竞赛-第1天】( 从头开始重新做题,记录备战竞赛路上的每一道题 )距离蓝桥杯还有75天

&#x1f3c6;&#x1f3c6;&#x1f3c6;&#x1f3c6;&#x1f3c6;&#x1f3c6;&#x1f3c6; 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&a…

2023年“华数杯”国际数模赛赛题浅析

2023华数杯如期开赛&#xff0c;本次比赛作为美赛的模拟赛&#xff0c;赛题和比赛时间都和美赛高度相似&#xff0c;因此大家 完全可以当作一次美赛之前的练习赛进行。美赛的发题时间与华数杯一致&#xff0c;都是早晨六点&#xff0c;现已经将机器翻译的初步翻译 结果进行了分…