并查集教程

/*
算法思想kruskal
①把图中所有边取出,排序
②取出top边,判断是否成环
终止条件:当添加的边数量==n-1(有答案)或者遍历完了所有边(无答案) 
初始条件:fa数组
*/
int n,m;//n顶点数,m边数 
int sum=0;//存答案 
int num=0;//存次数 
struct edge{
	int u,v,w;
}a[MAX];//存储边
 //这步不理解的,可以查看上面推荐的并查集教程
int findRoot(int t){
	if(fa[t]!=t)
		fa[t]=findRoot(fa[t]);
	return fa[t];
}
bool cmp(edge a,edge b){
	return a.w<b.w;
} 

int Kruskal(){
	//1初始化
	//并查集初始化
	int fa[MAX]; 	
	for(int i=1;i<=n;i++){
		fa[i]=i;
	} 
	//2算法核心
	//①排序 
	sort(a+1,a+m+1,cmp);
	//②取边,并判断是否成环 
	for(int i=1;i<=m;i++){
		//如果不成环  
		if(findRoot(a[i].u)!=findRoot(a[i].v)){
			//合并祖先
			fa[findRoot(a[i].u)]=findRoot(a[i].v)];
			ans+=a[i].w;
			num++;
		}
		if(num==n-1){
			cout<<ans<<'\n';
			return 0;
		}
	} 
	cout<<"error"<<'\n';
	return 0;
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

2.3.2 前缀和差分

声明一下,前缀和、差分是两个算法
一维、二维的前缀和、差分教学视频

2.3.3 二分法

二分法教程

2.4 中频算法

2.4.1 动态规划

之所以将动态规划划分到这里,是不想让你们死扣动态规划,动态规划考察的方法千变万化,很不容易掌握, 可能你学了之后,考试考到了一个别的,你还是不会,按照学习的性价比来说,动态规划的性价比没有前面的高。
动态规划有:线性DP,区间DP,背包问题,树形DP,数位DP,前三种相对于后两种来说,算是容易的,后两种比较难,考试基本不考,考到了也需要很熟练才能拿分,故在此处不展开叙述。

2.4.1.1 线性DP

在这里插入图片描述

数字三角形

/*
dp[i][j]表示从顶部走到第i行第j列经过的数字最大和
dp[i][j]=max(dp[i-1][j-1],dp[i-1][j])+aij
目标: dp[n][j]的最大值 (可以一维数组优化)
*/
dp[1][1]=a[1][1];
for(int i=2;i<=n;i++){
		for(int j=1;j<=i;j++){
			dp[i][j]=max(dp[i-1][j-1],dp[i-1][j])+a[i][j];
		}
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

最大连续子段和

/*
定义:dp[i]代表前i个元素的最大子段和的值 
转移:if(dp[i-1]>0) dp[i]=dp[i-1]+a[i]
	  else	dp[i]=a[i]
初始化:dp[i]=a[i];//可以优化a[i] 
目标:max(dp[i])
*/
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

最长公共子序列

/*
给定两个序列x和y,求x和y的最长公共子序列的长度 
定义:dp[i][j]表示x[1~i],y[1~j]的最长公共子序列长度 
转移:if(x[i]==y[j]) dp[i][j]=dp[i-1][j-1]+1
	  else if(x[i]!=y[j]) dp[i][j]=max(dp[i][j-1],dp[i-1][j])
初始化:dp[i][0]=0,dp[0][j]=0;
目标: dp[n][m]
*/
for(int i=0;i<=len1;i++)	dp[i][0]=0;
for(int j=0;j<=len2;j++)	dp[0][j]=0;
for(int i=1;i<=len1;i++){
	for(int j=1;j<=len2;j++){
		if(s1[i-1]==s2[j-1]){
			dp[i][j]=dp[i-1][j-1]+1;
		}else{
			dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
		}
	}
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

最长上升子序列

/*
定义:dp[i]表示前i个元素中的最长上升子序列 
转移:if(a[i]>a[j]) dp[i]=max(dp[j]+1,dp[i]);
初始化:dp[0]=0
目标: max(dp[i])
*/
for(int i=1;i<=n;i++){
		dp[i]=1;
		for(int j=1;j<i;j++){
			if(a[j]<a[i]){
				dp[i]=max(dp[i],dp[j]+1);
			}
		}
		if(dp[i]>MaxNum){
			MaxNum=dp[i];
		}
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
2.4.1.2 区间DP

游艇租赁

/*
定义:dp[i][j]表示第i个站点到第j个站点的最少租金 
转移:dp[i][j]=min( dp[i][k]+dp[k][j]  ,  dp[i][j]  ) 
初始化:dp[i][j]=a[i][j] 
目标: dp[1][n]
*/
for(int d=3;d<=n;d++){
	for(int i=1;i<=n-d+1;i++){
		int j=i+d-1;
		for(int k=i+1;k<j;k++){
			if(dp[i][j]>dp[i][k]+dp[k][j]){
				dp[i][j]=dp[i][k]+dp[k][j];
			}
		}
	}
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

回文问题
定义:dp[i][j]表示将字符串s的子区间[i][j]转化为回文串的最小成本
转移:if(s[i]==s[j]), dp[i][j]=dp[i+1][j-1]
if(s[i]!=s[j]),dp[i][j]=min(dp[i+1][j]+min(arr[i][0],arr[i][1]),dp[i][j-1]+min(arr[j][0],arr[j][1]))
初始化:dp[i][j]=0;
目标: dp[0][m-1]

在这里插入图片描述
括号匹配问题
定义:dp[i][j]表示字符串i到j区间的最长正则括号子序列的长度
转移:括号匹配分两种情况
情况①嵌套((()))
转移:if(s[i]==s[j]) dp[i][j]=dp[i+1][j-1]+2;
else dp[i][j]=max(dp[i+1][j],dp[i][j-1]);
情况②拼接 ()()()
转移:if(s[i]==s[j]) dp[i][j]=max(dp[i][k]+dp[k+1][j]); (k=i,i+1,…,j-1)
else dp[i][j]=max(dp[i+1][j],dp[i][j-1]);
初始化dp[i][j]=0
目标:dp[0][len-1]
在这里插入图片描述

2.4.1.3 背包问题

0-1背包问题:每个物品只有一个,只有放和不放两种可能
定义:dp[j]表示容量为j的背包放入前i种物品时的最大容量
转移:if(w[i]<=j) dp[j]=max(dp[j],dp[j-w[i]]+v[i]);(倒推,因为需要用到上一行的旧数据)
初始化:dp[j]=0;
目标: dp[m]
在这里插入图片描述
完全背包:物品有无限多个,可以放入的数量不可估量
定义:dp[j]表示容量为j的背包放入前i种物品时的最大容量
转移:if(w[i]<=j) dp[j]=max(dp[j],dp[j-w[i]]+v[i]);(正推,因为需要用到当前行的新数据)
初始化:dp[j]=0;
目标: dp[m]
在这里插入图片描述
多重背包:每个物品的数量有限

//思路:
//①暴力分解 转化成01背包 (容易超时n^3)
for(int i=1;i<=n;i++)
	for(int k=1;k<=c[i];k++)
		for(int j=m;j>=w[i];j--)
			dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
//②二进制分解 将ci个物品拆分成=2^0,2^1,2^2,2^3......+2^p,剩余部分为Ri=ci-(2^0+2^1+...+2^p) (logn^3)
for(int i=1;i<=n;i++){
		if(d[i]*w[i]>=m){//转化成完全背包 
			for(int j=w[i];j<=m;j++){
				dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
			}
		}else{
			for(int k=1;c[i]>0;k<<=1){//二进制拆分 
				int x=min(c[i],k);
				c[i]-=x;
				for(int j=m;j>=w[i]*x;j--){//转化成01背包 
					dp[j]=max(dp[j],dp[j-w[i]*x]+x*v[i]);
				}
			}
		}
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

分组背包

/*
定义:dp[j]表示将前i组物品放入容量为j的背包中可以获得的最大价值 
转移:dp[j]=max(dp[j],dp[j-w[i][k]]+v[i][k]);(倒推) 
初始化:dp[j]=0;
目标: dp[m];
*/
for(int i=1;i<=n;i++)//枚举组 
	for(int j=m;j>=0;j--)//枚举背包容量(倒推) 
		for(int k=1;k<=c[i];k++)//枚举组内每个物品 
			if(j>w[i][k])
				dp[j]=max(dp[j-w[i][k]]+v[i][k],dp[j]);
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

混合背包

//混合背包的模板
 for(int i=1;i<=n;i++){
	if(//01背包问题){
		ZeroOnePack(c[i],w[i]);
	}else if(//完全背包问题){
		CompletePack(c[i],w[i])
	}else if(//多重背包问题){
		MultiplePack(c[i],w[i],n[i])
	}
 }
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

3 辅助算法

这里的算法是不会单独考察的,而是穿插在其它算法里的一小步,掌握好辅助算法,可以帮助你快速做题。

3.1 排序

3.1.1 优先队列

//自定义类型
struct Node{
	int num;
	int mosst;
};
//重载自定义类型的比较运算符
//如果num相等,则mosst大的排前面;否则num大的排前面
struct cmpl{
	bool operator()(Node d1,Node d2){
		if(d1.num==d2.num){
			return d1.mosst>d2.mosst;
		}else{
			return d1.num>d2.num;
		}
	}
};
//定义priority_queue<类型1,容器<类型1>,重载的比较运算符>
priority_queue<Node,vector<Node>,cmpl> q;
//存储(存储进去后,自动按照指定的排序规则排序)
Node temp;
q.push(temp);
//拿栈顶元素
q.top();
//弹出栈顶元素
q.pop();
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

3.1.2 sort排序

①int数组

#include 
#include 
using namespace std;

int main() {
    int arr[] = {5, 2, 9, 1, 5, 6};
    int n = sizeof(arr) / sizeof(arr[0]);
    sort(begin(arr),end(arr)); // 使用 begin 和 end 获取数组边界
    for (int i = 0; i < n; ++i)
       cout << arr[i] << " ";
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

②vector类型

#include 
#include 
#include 
using namespace std;

int main() {
    vector<int> vec = {3, 1, 4, 1, 5, 9};
    sort(vec.begin(), vec.end());
    for (auto& v : vec)
        cout << v << " ";
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

③自定义类型

#include 
#include 
#include 
#include 
using namespace std;

struct Person {
    string name;
    int age;
    // 构造函数
    Person(string n, int a) : name(n), age(a) {}
};

// 比较函数
bool compare_by_age(const Person &a, const Person &b) {
    return a.age < b.age;
}

int main() {
    vector<Person> people = {
        Person("Alice", 30),
        Person("Bob", 25),
        Person("Charlie", 35)
    };

    // 使用自定义比较函数排序
    sort(people.begin(), people.end(), compare_by_age);

    for (const auto& person : people)
        cout << person.name << " " << person.age << "\n";
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

3.2 string 字符串使用

string s = "Hello World";
//求字符串长度
cout << "Size: " << s.size() << "\n"; // 或者使用 length()
//字符串判空
if (s.empty()) {
    cout << "String is empty\n";
}
//截取字符串
string sub = s.substr(0, 5); // 提取从索引0开始的5个字符
//查找子串位置
size_t pos = s.find("World"); // 查找 "World" 的位置
if (pos != string::npos) {
    cout << "Found at position: " << pos << "\n";
}
//插入字符串
s.insert(5, ", "); // 在索引5处插入 ", "
//比较字符串
string s1 = "Hello";
string s2 = "hello";
if (s1.compare(s2) == 0) {
    std::cout << "Strings are equal\n";
} else {
    std::cout << "Strings are not equal\n";
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

4 练习网站推荐

4.1 边学边练

4.1.1蓝桥杯题库

蓝桥杯 C/C++ 组历届真题合集
在这里你可以通过标签筛选练习题,来巩固你刚学过的算法
在这里插入图片描述

蓝桥成套真题演练
在这里面,你可以找到成套真题,适合用作考前模拟题,考试时间为4小时,平时学习时,可能边查资料边写代码,导致做题速度较慢,这到考场是致命的伤,一定要提前模拟!!
遗憾的是,这个题目是真实比赛时的试卷,不能判断你写的对错,如果要知道对错,你需要复制题目,到蓝桥杯 C/C++ 组历届真题合集这里面搜索对应的题目,再将题解复制过去,查看对错。
在这里插入图片描述

4.1.2 leetcode题库

leetcode题库
在这里,你可以筛选题目难度,题目标签
在这里插入图片描述
每道题都有题解,可以选择题解的语言类别,查看大佬们的思路,从而充实自己的大脑,终有一天,你也可以发布题解,得到多人的点赞
在这里插入图片描述

4.2 小试牛刀

4.2.1 蓝桥算法双周赛等

一些同学,可能觉得平常自己练习没有时间上的紧迫感,这里推荐一些小比赛,可以自己参加试试。
蓝桥竞赛这里面是蓝桥杯官方的一些比赛
在这里插入图片描述

4.2.2 leetcode竞赛

leetcode竞赛

在这里插入图片描述

4.2.3牛客竞赛

牛客竞赛,可以挑选赛制
在这里插入图片描述

4.3 其它

其实以上网站就足够你练习题目了,下面推荐的网站是几个也能练题的网站,学有余力可以做,但是如果你放弃上面三个做题网站,而选择下面几个,就是舍本逐末了。
洛谷
码蹄集
C语言网包含了很多题目集,也包括蓝桥杯的。
有些人喜欢在C语言网做蓝桥的题,可以参考这篇博文C语言网在ACM蓝桥杯等算法竞赛的妙用
Virtual Judge支持多个国际知名的在线编程竞赛平台,包含了北京大学,PTA,洛谷等,剩下很多需要翻墙才能访问,我也没用过,感兴趣可以自己研究。
在这里插入图片描述

5 赛前须知

第16届蓝桥杯报名官网每一届报名网址都不一样,比如第15届的报名网址就不是这个,所以如果未来想找第17届,第18届的,自己百度搜索第某某届蓝桥杯报名官网就行。
报名官网上可以看到大赛的最新消息,要学会自己查大赛的规则。
蓝桥别—>关于大赛—>比赛大纲
在这里插入图片描述
点开比赛大纲,第十六届蓝桥杯大赛软件赛和电子赛竞赛大纲,下载压缩包,查看大赛规则。

5.1 比赛要求(考前必看)

竞赛时长: 4小时(一般是上午9点到下午1点)
机器配置:
X86兼容机器,内存不小于4G,硬盘不小于60G。
操作系统:Windows7、Windows8、Windows10或Windows11
编程环境:
Dev-cpp 5.11(支持C++11标准)
C/C++ API 帮助文档

(建议大家平时练习时也使用这个环境,防止比赛时因为不熟悉而浪费时间)

5.2 Dev配置(考前必会)

一般学校机考,会给你下载好Dev和API帮助文档,但是全都是默认配置,需要你自己配置成自己习惯的使用方式。

5.2.1 设置为中文界面

http://iyenn.com/rec/1641036.html

5.2.2 使用C++11新标准

Dev5.11默认是不开启C++11标准的,可以选择开启

http://iyenn.com/rec/1641037.html
这里记住自己使用的Dev是哪个标准的:
如果配置了C++11标准,代码运行正常,那么提交时也选择C++11。
如果没有配置C++11标准,且代码运行正常,那么提交时选择C++即可。

5.2.3 Dev-C++环境下的degug使用

实话实说:其实Dev-C++5.11的调试功能,有严重的Debug。
经常在单步调试时,遇到卡住无法向下一步执行的问题。如果遇到了该问题,建议不要死磕,可以使用打印语句来模拟debug
(我找过很多解决方案,有的建议把endl换成"\n",但是调试时还是会卡住,相信我这个前人的话,不要死磕)
Dev-C++环境调试如何使用?

5.2.4 万能头文件

Dev中默认自带这个头文件,所以直接使用即可,无需配置

//加入这个头文件,就可以省去几乎所有你会用到的头文件了
//一些大佬不屑于使用这个头文件
//因为它包含了很多用不上的头文件,会稍稍影响编译性能
//但是我觉得对小白还是很友好的,我比赛时就一直使用的这个头文件,几乎没什么影响
#include
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

5.3 考试答疑

5.3.1 提交时如何选择编译环境?

官方提醒!!!
在这里插入图片描述
如何知道自己平时练习时使用的环境呢?
在这里插入图片描述
平时蓝桥官网提交的C++(g++17)都是支持c++11的。由于蓝桥杯是OI赛制,即提交后不反馈分数,如果因为编译器选择错误,导致丢分,将非常可惜。为了万无一失,建议使用自己的Dev环境模拟比赛环境(上面5.2.2已经介绍)

5.3.2 考试时可以上厕所吗?

可以的。征得监考老师同意就可以去,毕竟考试时长4小时,不可能不让你上厕所。

5.3.3 可以带纸和笔吗?

可以的,可以带上纸和笔。有的学校是自己发放草稿纸,这时只需带笔就行。

5.3.4 用谁的电脑?

一般是使用机房电脑,学校统一组织监考。
请注意:如果学校机房的电脑比较破旧,答题文件请保存在除了C盘以外的盘符,并实时保存。
(因为学校电脑破旧,所以可能会卡顿,蓝屏,这时就需要重启电脑,而我们学校的电脑是重启会自动清空C盘,只留操作系统,如果你的题目保留在C盘,那么恭喜你前功尽弃,重新开始答题)

注:本文转载自blog.csdn.net的无缘之缘的文章"https://blog.csdn.net/lhllhllhl_/article/details/144973272"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接

评论记录:

未查询到任何数据!