这里是paoxiaomo,一个现役ACMer,之后将会持续更新算法笔记系列以及笔试题题解系列
本文章面向想打ICPC/蓝桥杯/天梯赛等程序设计竞赛,以及各个大厂笔试的选手
感谢大家的订阅➕ 和 喜欢💗
有什么想看的算法专题可以私信博主
(本文题面由清隆学长收集)
01.K小姐的基环树游戏
问题描述
K小姐最近迷上了一款基环树游戏。这个游戏的游戏地图是一个无向图,图中有 n n n 个节点和 m m m 条边,且不包含重边和自环。在这个游戏中,玩家需要在图上再选择连接一条边,使得整个无向图变成一棵基环树。
所谓基环树,是一种包含 n n n 个节点, n n n 条边,且不包含重边和自环的无向连通图。形象地说,基环树可以由一棵普通的树再添加一条之前不存在的边构成。
现在,K小姐想知道,对于当前的游戏地图,一共有多少种不同的连边方案可以使其变成一棵基环树呢?
输入格式
第一行输入两个正整数 n , m n,m n,m,代表无向图的节点数和边数。
接下来的 m m m 行,每行输入两个正整数 u , v u,v u,v,代表节点 u u u 和节点 v v v 之间有一条边相连。保证给定的无向图中不存在重边和自环。
输出格式
输出一个整数,代表添加一条新边使其变成基环树的方案数。
样例输入
4 4
1 2
1 3
2 3
2 4
样例输出
0
在这个样例中,原图已经是一棵基环树了,因此不需要再添加新边,方案数为0。
数据范围
1 ≤ n , m ≤ 1 0 5 1 \le n, m \le 10^5 1≤n,m≤105
1 ≤ u , v ≤ n 1 \le u, v \le n 1≤u,v≤n
【试题解析】
这个问题可以使用图论的知识来解决。基环树是一种特殊的图,它是一棵树加上一条额外的边构成的。要将一个无向图变成基环树,需要找到一种方法在当前的图上添加一条边,使得整个图成为基环树。
可以使用并查集来解决这个问题。首先,我们需要判断给定的无向图是否是一棵树,然后再找到可以添加的边数目。
#include <iostream>
using namespace std;
class UnionFind {
//并查集板子
private:
vector<int> parent, rank;
public:
UnionFind(int n) {
parent.resize(n);
rank.resize(n, 0);
for (int i = 0; i < n; ++i)
parent[i] = i;
}
int find(int x) {
return parent[x] == x ? x : (parent[x] = find(parent[x]));
}
void unite(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
if (rank[rootX] < rank[rootY])
swap(rootX, rootY);
parent[rootY] = rootX;
if (rank[rootX] == rank[rootY])
rank[rootX]++;
}
}
};
int main() {
int n, m;
cin >> n >> m;
UnionFind uf(n);
bool isTree = true;
for (int i = 0; i < m; ++i) {
int u, v;
cin >> u >> v;
if (uf.find(u - 1) == uf.find(v - 1)) {
isTree = false;
}
uf.unite(u - 1, v - 1);
}
if (!isTree || m != n - 1) {
cout << 0 << endl;
return 0;
}
cout << 1 << endl;
return 0;
}
02.魔法糖果屋
问题描述
小美是一个贪吃的小朋友,有一天她发现了一个装满魔法糖果的糖果屋。糖果屋里一共有 n n n 颗糖果,第 i i i 颗糖果上写着数字 a i a_i ai。
小美每天都必须吃一颗糖果,而且第 x x x 天必须吃一颗写着数字 x x x 的糖果。小美有一个魔法棒,可以用来改变一颗糖果上的数字,将其变成原来的两倍。但魔法棒只能使用一次。
小美想知道使用魔法棒一次之后,自己最多能连续吃到糖果的天数是多少呢?你能帮帮她吗?
输入格式
第一行包含一个正整数 n n n,表示糖果的数量。
第二行包含 n n n 个正整数 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2