bool judge(int root) {
if ( == -1) return true;
queue<int> q;
q.push(root);
while (!q.empty()) {
int tmp = q.front();
q.pop();
if (tmp != -1) {
q.push(node[tmp].left);
q.push(node[tmp].right);
}
else {
while (!q.empty()) {
tmp = q.front();
q.pop();
if (tmp != -1)
return false;
}
}
}
return true;
}
bool judge(node *root) {
queue<node*> q;
q.push(root);
while(!q.empty()) {
node *u = q.front();
q.pop();
if (u != NULL) {
q.push(u->left);
q.push(u->right);
}
else {
while(!q.empty()) {
u = q.front();
q.pop();
if (u != NULL)
return false;
}
}
}
return true;
}
并查集
考察的题目有:
序号
类型
题目
1
找到每个人归属的社群
2
计算家族房产
3
判断鸟儿是否属于同一棵树
// 并查集主要就是两个操作,一个查找,一个合并
// 需要的数据结构为数组,存储自己的parent
int fa[maxn] = {0};
// find为algorithm中的函数,所以这里的Find首字母大写
int Find(int i) {
int root = i;
while(root != fa[root])
root = fa[root];
// 路径压缩
int t = i;
int p;
while (t != root) {
p = fa[t];
fa[t] = root;
t = p;
}
return root;
}
// union为关键字,写的时候要注意
void Union(int i, int j) {
int ri = find(i);
int rj = find(j);
if (ri != rj)
fa[ri] = rj;
}
#include <iostream>
#include <queue>
using namespace std;
priority_queue<long long, vector<long long>, greater<long long> > q;
int main()
{
int n;
long long temp, x, y, ans = 0;
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%lld", &temp);
q.push(temp);
}
while(q.size() > 1) {
x = q.top();
q.pop();
y = q.top();
q.pop();
q.push(x + y);
ans += (x + y);
}
printf("%lld", ans);
}
图
dfs+dijkstra 1087.All Roads Lead to Rome (30分)
Dijkstra算法
// 代码来自《算法笔记》和柳神的Github
// 调整了大写字母,在比赛或者考试中尽量选择好打的字母,大写字符输入较慢
// 邻接矩阵版本
// 这里为了注释的方便,一个变量写成一行,运用时直接写到一行即可
// n为顶点数目
int e[maxv][maxv]; // e为记录边的邻接矩阵, maxv为最大顶点数
int dis[maxv]; // 顶点的距离数组
bool visit[maxv]; // 访问数组
const int inf = 99999999;
fill(e[0], e[0] + maxv * maxv, inf);
fill(dis, dis + maxv, inf);
dis[0] = 0;
for (int i = 0; i < n; ++i) {
int u = -1, minn = inf;
// 这里的查找可以用堆排序来实现降低时间复杂度
// 但是比赛过程再去实现一个堆排序不是我们的目的,直接遍历查找就好
for (int j = 0; j < n; ++j) {
if (visit[j] == false && dis[j] < minn) {
u = j;
minn = dis[j];
}
}
if (u == -1) break;
visit[u] = true;
for (int v = 0; v < n; v++) {
if (visit[v] == false && e[u][v] != inf && dis[v] > dis[u] + e[u][v])
dis[v] = dis[u] + e[u][v];
}
}
// 邻接表版本
struct Node {
int v, dis;
};
vector<Node> Adj[maxv];
int n;
int d[maxv];
bool vis[maxv] = {false};
void Dijkstra(int s) {
fill(d, d + maxv, inf);
d[s] = 0;
for (int i = 0; i < n; ++i) {
int u = -1, minn = inf;
for (int j = 0; j < n; ++j) {
if (vis[j] == false && d[j] < minn) {
u = j;
minn = d[j];
}
}
if (u == -1) return;
vis[u] = true;
for (int j = 0; j < Adj[u].size(); j++) {
int v = Adj[u][j].v;
if (vis[v] == false && d[u] + Adj[u][v].dis < d[v]) {
d[v] = Adj[u][v].dis + d[v];
}
}
}
}
Floyd算法
const int inf = 99999999;
const int maxv = 200;
int n, m;
int dis[maxv][maxv];
void Floyd() {
for (int k = 0; k < n; ++k) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (dis[i][k] != inf && dis[k][j] != inf && dis[i][k] + dis[k][j] < dis[i][j])
dis[i][j] = dis[i][k] + dis[k][j];
}
}
}
}
拓扑排序
考察题型:
序号
类型
题目
1
判断是否为序列是否满足拓扑排序
vector<int> G[maxv];
int n, m, indegree[maxv];
bool topologicalSort() {
int num = 0;
queue<int> q;
for (int i = 0; i < n; ++i) {
if (indegree[i] == 0)
q.push(i);
}
while(!q.empty()) {
int u = q.front();
printf("%d", u);
q.pop();
for (int i = 0; i < G[u].size(); ++i) {
int v = G[u][i];
indegree[v]--;
if (indegree[v] == 0)
q.push(v);
}
num++;
}
if (num == n) return true; // 拓扑排序成功
else return false;
}
算术运算
这两道题的核心是最大公约数的求法,使用辗转相除法
序号
类型
题目
1
有理数分数求和
2
有理数分数四则运算
最大公约数
/*
例子:求1071 和462的最大公约数
使用的方法是:辗转相除法
1071 = 2 X 462 + 147 a = 1071, b = 462
462 = 3 X 147 + 21 a = 462 , b = 147
147 = 7 X 21 + 0 a = 147 , b = 21
a = 21 , b = 0
*/
long long gcd (long long a, long long b) {
return (b == 0)? abs(a) : gcd(b, a % b);
}
最小公倍数
long long lcm(long long a, long long b) {
long long d = gcd(a, b);
return (a/d)*b;
}
素数判断
考察题目:
序号
类型
题目
1
将数值分解成质因子相乘
bool isPrime(int n) {
if (n <= 1) return false;
int sqr = int(sqrt(n * 1.0));
for (int i = 2; i <= sqr; i++) {
if (n % i == 0)
return false;
}
return true;
}
// 素数表, 找到从[2~maxn)中的所有素数
const int maxn = 101;
int prime[maxn];
int pNum = 0; // 素数表的下标
bool p[maxn] = {0}; // 记录[2, maxn)中每个数是否访问过
void Find_Prime() {
for (int i = 2; i < maxn; ++i) {
if (p[i] == false) {
prime[pNum++] = i;
// 存在i的倍数的数值一定不是素数, 2i, 3i ....
for (int j = i +i; j < maxn; j += i) {
p[j] = true;
}
}
}
}
// 将sum转换成d进制
int ans[31], num = 0;
do {
ans[num++] = sum % d;
sum /= d;
} while(sum!= 0);
// d进制转换成十进制
int ans, product = 1;
while(x != 0) {
y = y + (x % 10)*product;
x = x/10;
product = product * d;
}
int tsize, n, m, a;
cin >> tsize >> n >> m;
while(!isPrime(tsize)) tsize++;
vector<int> v(tsize);
for (int i = 0; i < n; ++i) {
scanf("%d", &a);
int flag = 0;
for (int j = 0; j < tsize; j++) {// 这里j的取值范围只要[0, tsize)
int pos = (a + j * j ) % tsize;
if (v[pos] == 0) {
v[pos] = a;
flag = 1;
break;
}
}
if (!flag) printf("%d cannot be inserted.\n", a);
}
int ans = 0;
for (int i = 0; i < m; ++i) {
scanf("%d", &a);
// find a
for (int j = 0; j <= tsize; j++) {
ans ++;
int pos = (a + j * j) % tsize;
if (v[pos] == a || v[pos] == 0) break;
}
}
void bubbleSort(int arr[], int n) {
bool NoSwap;
for (int i = 0; i < n - 1; ++i) {
NoSwap = true;
for (int j = n - 1; j > i; --j) {
if (arr[j] < arr[j - 1]) {
swap(arr[j], arr[j - 1]);
NoSwap = false;
}
}
if (NoSwap) return;
}
}
选择排序
void selecetSort(int arr[], int n) {
for (int i = 0; i < n-1; ++i) {
int k = i;
// 找到序列中未排序的最小元素
for (int j = i+1; j < n; ++j) {
if (arr[j] < arr[i])
k = j;
}
swap(arr[i], arr[k]);
}
}
插入排序
void insertSort(int arr[], int n) {
for (int i = 1; i < n; ++i) {
int temp = arr[i], j = i;
// 找到已排序中的插入位置
while(j > 0 && temp < arr[j]) {
arr[j] = arr[j-1];
j--;
}
arr[j] = temp;
}
}
快速排序
考察题型:
序号
类型
题目
1
判断序列元素是否可以作为pivot
void quickSort(int arr[], int left, int right) {
if (right <= left) return;
int pivot = selectPivot(left, right);
swap(arr, pivot, right);
pivot = partion(arr, left, right);
quickSort(arr, left, pivot - 1);
quickSort(arr, pivot + 1, right);
}
int selectPivot(int left, int right) {
return (left + right)/2;
}
int partion(int arr[], int left, int right) {
int l = left;
int r = right;
int temp = arr[right];
while(l != r) {
while(arr[l] <= temp && r > l)
l++;
if (l < r) {
arr[r] = arr[l];
r--;
}
while(arr[r] >= temp && r > l)
r--;
if (l < r) {
arr[l] = arr[r];
l++
}
}
arr[l] = temp;
return l;
}
归并排序
const int maxn = 100;
// 归并排序归并的是相邻的两个区间,[L1,R1]和[L2, R2]
void merge(int A[], int L1, int R1, int L2, int R2) {
int i = L1, j = L2; 、、
int temp[maxn], index = 0;
while(i <= R1 && j <= R2) {
if (A[i] <= A[j])
temp[index++] = A[i++];
else
temp[index++] = B[j++];
}
// 移动剩下的区间
while(i <= R1) temp[index++] = A[i++];
while(j <= R2) temp[index++] = B[j++];
for(int i = 0; i < index; i++) {
A[L1+i] = temp[i];
}
}
void mergeSort(int A[], int left, int right) {
if (left < right) {
int mid = (left + right) /2;
mergeSort(A, left, mid);
mergeSort(A, mid+1, right);
merge(A, left, mid, mid + 1, right);
}
}
// 非递归版本
void mergeSort(int A[]) {
// 每组step长度,前step/2和后step/2的元素合并
for (int setp = 2; step / 2 <= n; step *= 2) {
for (int i = 1; i <= n; i+= step) {
int mid = i + step / 2 - 1;
if (mid + 1 < n) {
merget(A, i, mid, mid + 1, min(i + step - 1, n);
}
}
}
}
// 用sort函数替代merge函数,A1089题用到
void mergeSort(int A[]) {
for (int step = 2; step / 2 <= n; step *= 2) {
for (int i = 1; i < n; i+= step)
sort(A + i, A + min(i + step, n + 1));
// 这里可以输出每一趟归并结果
}
}
typedef long long LL;
LL binaryPow(LL a, LL b, LL m) {
if (b==0) return 1;
if (b % 2 == 1) return a * binaryPow(a, b - 1, m) % m;
else {
LL mul = binaryPow(a, b / 2, m);
return mul * mul %m;
}
}
n!有多少个质因子P
int cal(int n, int p) {
int ans = 0;
while(n) {
ans += n / p;
n /= p;
}
return ans;
}
int cal(int n, int p) {
if (n / p) return 0;
return n/p + cal(n / p, p);
}
组合数
long long C(long long n, long long m) {
if ( == 0|| m == n) return 1;
return C(n - 1, m) + C(n - 1, m - 1);
}