前言:由于时间真不多了。。。之后的专题都会是题目加代码,可能会有一点分析。。。我真的复习不完了~~~
第五个专题:树形结构。
并查集和最小生成树的算法:kruskal。比较重要的两个算法。
有关题目:CSP 2018-12-T4。
首先要抓住这几个要素:无向图、有边权、求最小生成树。
这题本意就是要求最小生成树中最大的边。
首先说一下kruskal的执行过程:适用于无向图,首先从图中选取最小的边权,放入到一个集合中,从原图去掉该边。接下来一直从图中取最小边权的边,但有一个条件,取出来的边不能够成环路,如果构成环路,那么要去掉这条边从再从图中找。直到集合中所有的边构成了一个无环路的树,这棵树就是最小生成树。
而最大边就是最后一次取出来的。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
#define MAX 100005
struct edge
{
int x, y;
int w;
}e[MAX];
int fa[MAX];
int ans;
int cmp(edge a, edge b)//排序函数
{
if (a.w != b.w)
return a.w<b.w;
else
{
return a.x<b.x;
}
}
void make_set(int x)//初始化节点
{
fa[x] = x;
}
int find(int x)//查找父节点
{
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void union_set(int x, int y, int w)//合并节点
{
fa[y]=x;
if (ans<w)
{
ans = w;
}
}
int main()
{
int x, y, w;
int m, n, root;//n是点,m是边
cin >> n >> m >> root;
for (int i = 0; i<m; i++)
{
cin >> x >> y >> w;
e[i].x = x;
e[i].y = y;
e[i].w = w;
make_set(x);
make_set(y);
}
sort(e, e + m, cmp);
ans = 0;
for (int i = 0; i<m; i++)
{
x = find(e[i].x);
y = find(e[i].y);
w = e[i].w;
if (x != y)
{
union_set(x, y, w);
}
}
cout << ans << endl;
return 0;
}
这份代码是靠“点”来判断是否构成了图的回路。
本章还接着CSP的题目布置了CSP 2018-12-T2的作业,一并附上代码。
题目:
问题描述
一次放学的时候,小明已经规划好了自己回家的路线,并且能够预测经过各个路段的时间。同时,小明通过学校里安装的“智慧光明”终端,看到了出发时刻路上经过的所有红绿灯的指示状态。请帮忙计算小明此次回家所需要的时间。
输入格式
输入的第一行包含空格分隔的三个正整数 r、y、g,表示红绿灯的设置。这三个数均不超过 10^6。
输入的第二行包含一个正整数 n,表示小明总共经过的道路段数和路过的红绿灯数目。
接下来的 n 行,每行包含空格分隔的两个整数 k、t。k=0 表示经过了一段道路,将会耗时 t 秒,此处 t 不超过 10^6;k=1、2、3 时,分别表示出发时刻,此处的红绿灯状态是红灯、黄灯、绿灯,且倒计时显示牌上显示的数字是 t,此处 t 分别不会超过 r、y、g。
输出格式
输出一个数字,表示此次小明放学回家所用的时间。
题解:就是一个按照红绿灯顺序,建立了一个长的时间序列,判断时间进行时,所到路口的红绿灯情况。每过一个路口就增加一定的时间。
注意红绿灯顺序是:黄灯、红灯、绿灯
代码:
#include<iostream>
using namespace std;
int r,y,g;
int tim(int x)
{
if(x>y+r) return 0;
else return y+r-x;
}
int main()
{
//int r,y,g;
cin>>r>>y>>g;
int n;
cin>>n;
int k,t;
long long sum=0;
while(n--)
{
cin>>k>>t;
if(k==0) sum+=t;
else if(k==1) sum+=tim((y+r-t+sum)%(y+r+g));
else if(k==2) sum+=tim((y-t+sum)%(y+r+g));
else sum+=tim((y+r+g-t+sum)%(y+r+g));
}
cout<<sum<<endl;
return 0;
}