一些要背的模板~(填坑中)
- 完成
注意事项
- 完成
搜索
- 完成
DFS(深搜)
Depth First Search
- 完成
#include<bits/stdc++.h>
using namespace std;
int n, vis[12], num[12];
void dfs(int cnt){
if(cnt == n){
//TODO
return;
}
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
num[cnt+1]=i;
vis[i]=1;
dfs(cnt+1);
vis[i]=0;
}
}
}
int main(){
cin >> n;
dfs(0);
return 0;
}
BFS(宽搜)
Breath First Search
- 完成
void bfs(s){
queue<int> q;
q.push(s);
visited[s] = 1;
while (!q.empty()){
u = q.top();
q.pop();
for (与s相连的点v){
if (!visited[v]){
q.push(v);
visited[v] = 1;
}
}
}
}
中间相遇
- 完成
图论
- 完成
储存
- 完成
1.邻接数组(邻接矩阵)
- 完成
#include<bits/stdc++.h>
using namespace std;
const int INF = 1 << 30;
int graph[105][105];
int main(){
int n, m;//点数,边数
int a, b, c;//起点,重点,边权
cin >> n >> m;
for(int i=1;i<=n;i++)//初始化
for(int j=1;j<=n;j++)
if(i == j)
graph[i][j] = 0;
else
graph[i][j] = INF;
for(int i=1;i<=m;i++){//输入
cin >> a >> b >> c;
graph[a][b] = c;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(graph[i][j] != 0 && graph[i][j] != INF)
cout << i << " " << j << " " << graph[i][j];
return 0;
}
2.邻接链表
- 完成
#include<bits/stdc++.h>
using namespace std;
struct node{
int to, w;//终点,边权
};
vector<node> v[105];
int main(){
int n, m;//点数,边数
int a, b, c;//起点,终点,边权
cin >> n >> m;
for(int i=1;i<=m;i++)//初始化
v[i].clear();
for(int i=1;i<=m;i++){//建边
cin >> a >> b >> c;
v[a].push_back(node{b, c});
}
for(int i=1;i<=n;i++)
for(int j=0;j<v[i].size();j++)
cout << i << " " << v[i][j].to << " " << v[i][j].w << endl;
return 0;
}
3.链式前向星(边表)
- 完成
#include<bits/stdc++.h>
using namespace std;
const int INF = 1 << 30;
int head[105], num = 0;//head[i]:以i为起点的最后一条边的下标
struct node{
int to;//终点
int w;//边权
int nextt;//上一条边的下标
}edge[105];
void insert_edge(int x, int y, int z){//插入边表
edge[num].to = y;
edge[num].w = z;
edge[num].nextt = head[x];
head[x] = num++;
}
int main(){
int n, m;
int a, b, c;
cin >> n >> m;
memset(head, -1, sizeof(head));
for(int i=1;i<=m;i++){
cin >> a >> b >> c;
insert_edge(a, b, c);
}
for(int i=1;i<=n;i++)
for(int j=head[i];~j;j = edge[j].nextt)
cout << i << " " << edge[j].to << " " << edge[j].w << endl;
return 0;
}
遍历
- 完成
深搜遍历
- 完成
#include<bits/stdc++.h>
using namespace std;
int vis[105];//标记点是否被访问过
vector<int> v[105];
int s;//起点
void DFS(int u){
vis[u] = 1;
cout << u;
for(int i=0;i<v[u].size();i++)
if(vis[v[u][i]] == 0)
DFS(v[u][i]);
}
int main(){
int n, m;//点数,边数
int a, b;//起点,终点
cin >> n >> m;
memset(vis, 0, sizeof(vis));
for(int i=1;i<=m;i++){//建边
cin >> a >> b;
v[a].push_back(b);
}
s = 1;
DFS(s);
return 0;
}
广搜遍历
- 完成
#include<bits/stdc++.h>
using namespace std;
int vis[105];//标记点是否被访问过
vector<int> v[105];
queue<int> q;
void BFS(){
int s = 1;
q.push(s);
vis[s] = 1;
while(!q.empty()){
int u = q.front();
q.pop();
cout << u;
for(int i=0;i<v[u].size();i++){
int V = v[u][i];
if(!vis[V]){
q.push(V);
vis[V] = 1;
}
}
}
}
int main(){
int n, m;//点数,边数
int a, b;//起点,终点
cin >> n >> m;
memset(vis, 0, sizeof(vis));
for(int i=1;i<=m;i++){//建边
cin >> a >> b;
v[a].push_back(b);
}
BFS();
return 0;
}
拓扑排序
- 完成
#include<bits/stdc++.h>
using namespace std;
#define maxn 110
int n;
vector<int> a[maxn];//使用vector邻接表储存图信息
int into[maxn];//into数组表示节点入度值
vector<int> ans;//ans储存最后序列
void init(){//输入,初始化图
cin >> n;
int s, t;
while(scanf("%d%d", &s, &t) == 2){
a[s].push_back(t);
into[t]++;
}
}
queue<int> q;
void TPSort(){
for(int i=1;i<=n;i++)
if(into[i] == 0)
q.push(i);
while (!q.empty()){//使用BFS搜索
int u = q.front();//取队首顶点u
q.pop();//将u删除
ans.push_back(u);
for(int i=0;i<a[u].size();i++){
//将从u出发的边删除
int v = a[u][i];
into[v]--;//对应边的终点入度减1
if (into[v] == 0)//如果v点入度为0,将v入队
q.push(v);
}
}
if(ans.size() < n)
cout << -1;
else
for(int i=0;i<ans.size();i++)
cout << ans[i] << " ";
}
int main() {
init();
TPsort();
return 0;
}
最短路
- 完成
Dijkstra
- 完成
一个点到其他点(单源)
1.朴素
- 完成
2.堆优化
- 完成
#include<bits/stdc++.h>
using namespace std;
int head[100010], cnt, dis[100010], n, m, s, u, v, w;
priority_queue<pair<int, int> > q;
struct node{
int v, w, next;
}edge[200010];
bool visit[100010];
void add(int u, int v, int w){
edge[++cnt].v = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt;
}
void dijkstra(){
while(!q.empty()){
int num = q.top().second;
q.pop();
if(visit[num])
continue;
visit[num] = 1;
for(int i=head[num];i;i=edge[i].next)
if(dis[edge[i].v] > dis[num] + edge[i].w){
dis[edge[i].v] = dis[num] + edge[i].w;
q.push(make_pair(-dis[edge[i].v], edge[i].v));
}
}
}
int main(){
cin >> n >> m >> s;
for(int i=1;i<=m;i++){
cin >> u >> v >> w;
add(u, v, w);
}
for(int i=1;i<=n;i++)
dis[i] = 1e10;
dis[s] = 0;
q.push(make_pair(0, s));
dijkstra();
for(int i=1;i<=n;i++)
cout << dis[i] << " ";
return 0;
}
Bell-man Ford
- 完成
//"GmonkeYC!"是什么鬼
//已通过
#include<bits/stdc++.h>
using namespace std;
struct edge{
int from, to, val;
};
int d[1004];
edge ed[40004];
int main(){
// freopen("bellmanford.in", "r", stdin);
// freopen("bellmanford.out", "w", stdout);
ios::sync_with_stdio(false);
int n, m, s;
cin >> n >> m >> s;
for(int i=1;i<=m;i++){
int u, v, w;
cin >> u >> v >> w;
ed[i].from = u;
ed[i].to = v;
ed[i].val = w;
}
// for(int i=1;i<=m;i++){
// cout << ed[i].from << " " << ed[i].to << " " << ed[i].val << endl;
// }
memset(d, 0x3f, sizeof(d));
d[s] = 0;
//求最短路(良心代码量)
for (int i = 1; i < n; i++)
for (int j = 1; j <= m; j++)
d[ed[j].to] = min(d[ed[j].to], d[ed[j].from] + ed[j].val);
//输出
//bool flag = 0;
for (int j = 1; j <= m; j++)
if (d[ed[j].to] > d[ed[j].from] + ed[j].val){
//flag = 1;
cout << "GmonkeYC!";
return 0;
}
// if(flag == 1){
// cout << "GmonkeYC!";
// return 0;
// }
for(int i=1;i<=n;i++){
if(d[i] > 100000){
cout << -1;
continue;
}
cout << d[i] << endl;
}
return 0;
}
/*
memset(d, 0x3f, sizeof(d)), d[s] = 0; // 初始化
for (int i = 1; i < n; i++) // 共进行 n - 1 轮
for (int j = 1; j <= m; j++)
d[ed[j].to] = min(d[ed[j].to], d[ed[j].from] + ed[j].val); // 松弛操作
bool flag = 0;
for (int j = 1; j <= m; j++)
if (d[ed[j].to] > d[ed[j].from] + ed[j].val) flag = 1;
// 判断最短路是否存在
return 0;
*/
SPFA
- 完成
#include<bits/stdc++.h>
using namespace std;
const int maxn = 10001;
const int maxm = 10001;
int head[maxn], cnt = 0;
struct node{
int u, v, w, nextt;
}edge[maxm * 2];
void add(int u, int v, int w){
edge[++cnt].u = u;
edge[cnt].v = v;
edge[cnt].w = w;
edge[cnt].nextt = head[u];
head[u] = cnt;
}
int n, m;
int dis[maxn], sum[maxn];
bool vis[maxn];
queue<int> q;
bool spfa(int u){
memset(dis, 0x3f, sizeof(dis));
memset(vis, 0, sizeof(vis));
memset(sum, 0, sizeof(sum));
dis[u] = 0;
q.push(u);
vis[u] = 1;
sum[u]++;
while(!q.empty()){
int x = q.front();
q.pop();
vis[x] = 0;
for(int i=head[x];i;i=edge[i].nextt){
int t = edge[i].v;
if(dis[t] > dis[x] + edge[i].w){
dis[t] = dis[x] + edge[i].w;
if(!vis[t]){
if(++sum[t] >= n)
return 1;
vis[t] = 1;
q.push(t);
}
}
}
}
return 0;
}
void print(){
for(int i=1;i<=n;i++)
cout << dis[i] << " ";
}
int main(){
int s, x, y, z;
cin >> n >> m >> s;
for(int i=1;i<=m;i++){
cin >> x >> y >> z;
add(x, y, z);
}
bool ans;
if(!ans)
print();
else
cout << "负环";
return 0;
}
Floyd
- 完成
任意两点(多源)
#include<bits/stdc++.h>
using namespace std;
int main(){
// freopen("floyd.in", "r", stdin);
// freopen("floyd.out", "w", stdout);
ios::sync_with_stdio(false);
int n, m;
cin >> n >> m;
int f[n+4][n+4];
memset(f, 0x3f, sizeof(f));
for(int i=1;i<=n;i++){
f[i][i] = 0;
}
for(int i=1;i<=m;i++){
int u, v, w;
cin >> u >> v >> w;
f[u][v] = min(w, f[u][v]);
f[v][u] = min(w, f[u][v]);
}
for (int k = 1; k <= n; k++) // 中间变量记得放外面枚举
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
if(f[i][j] > 8000000)
cout << -1 << " ";
else
cout << f[i][j] << " ";
cout << endl;
}
return 0;
}
/*
for (int k = 1; k <= n; k++) // 中间变量记得放外面枚举
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
*/
最小生成树
- 完成
//最小生成树:Prim算法+邻接矩阵储存
//复杂度:n^2
#include<bits/stdc++.h>
using namespace std;
int w[5001][5001];//边的权值
int Min[5001];//蓝点的最小边权
bool B[5001];//蓝点标记
int MST = 0;//最小生成树权值和
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout .tie(0);
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
int n, m;//顶点数和边数
cin >> n >> m;
//初始化w
memset(w, 127, sizeof(w));
for(int i=1;i<=m;i++){
int x, y, z;
cin >> x >> y >> z;
w[x][y] = min(w[x][y], z);
w[y][x] = min(w[y][x], z);
}
//初始化Min, B;
memset(Min, 127, sizeof(Min));//初始化为最大
memset(B, 1, sizeof(B));//初始化为蓝点
Min[1] = 0;
//求解最小生成树
for(int i=1;i<=n;i++){//寻找Min[k]最小的蓝点k
int k = 0;
for(int j=1;j<=n;j++)
if(B[j] && Min[j] < Min[k])
k = j;
B[k] = 0;//洗白点k
MST += Min[k];//累加生成树权值
//修改与k相连的所有蓝点
for(int j=1;j<=n;j++)
if(B[j] && w[k][j] < Min[j])
Min[j] = w[k][j];
}
bool mark = 0;
for(int i=1;i<=n;i++)
if(B[i])
mark = 1;
if(mark)
cout << "orz";//图不连通
else
cout << MST;
return 0;
}
哈密顿环
- 完成
#include<bits/stdc++.h>
using namespace std;
const int mx = 10004;
int A[mx][mx];//邻接点存储
int num[mx];//计数器
bool visit[mx];//访问标记
int start, path[mx];//起点,路径
int n, m;//顶点数和边数
void print(int);
//last是上次访问的点,i是当前访问的点,step是步数
void dfs(int last, int i, int step){
// cout << i << " ";
path[step] = i;//记录路径
visit[i] = 1;//标记i已访问
for(int j=1;j<=num[i];j++){//循环i的邻接点
// 回到起点 避免回头 走完所有点
if(A[i][j] == start && A[i][j] != last && step == n){
path[n+1] = start;
print(n+1);//输出路径
}
if(!visit[A[i][j]])
dfs(i, A[i][j], step+1);//深搜一步
}
visit[i] = 0;//回溯
}
void print(int step){
for(int i=1;i<step;i++)
cout << path[i] << "--";
cout << path[step] << endl;
}
int main(){
int x, y;
n = 4, m = 5;
int a[9][9] = {{1, 2}, {1, 3}, {2, 3}, {2, 4}, {3, 4}};
for(int i=1;i<=m;i++){
x = a[i-1][0];
y = a[i-1][1];
A[x][++num[x]] = y;
A[y][++num[y]] = x;
}
cout << "哈密顿环" << endl;
for(start=1;start<=n;start++){
dfs(start, start, 1);
}
return 0;
}
ST表
- 完成
用来求区间最值
O
(
n
l
o
g
n
)
O(n log n)
O(nlogn)
#include<bits/stdc++.h>
using namespace std;
int st[100004][24];
int loglong[100004];
int main(){
loglong[0] = -1;
long long n, m, q;
cin >> n >> m >> q;
//输入
for(int i=1;i<=n;i++){
cin >> st[i][0];
loglong[i] = loglong[i/2]+1;//预处理log数组
}
//预处理ST表
for(int i=1;i<=loglong[n];i++){
for(int j=1;j+(1<<i)-1<=n;j++){
st[j][i]=max(stamax[j][i-1],stamax[j+(1<<(i-1))][i-1]);
//询问
while(q--){
int l, r;
cin>>l>>r;
cout << max(st[l][logg[r-l+1]], st[r-(1<<logg[r-l+1])+1][logg[r-l+1]]);
}
return 0;
}
线段树
- 完成
用来求区间最值
O
(
n
l
o
g
n
)
O(n log n)
O(nlogn)
数学
- 完成
gcd(最大公因数)
- 完成
手写
int gcdd(int x, int y){
return y?gcdd(y,x%y):x;
}
自带(c++14)
int a = __gcd(x, y);
lcm(最小公倍数)
- 完成
等于 a ∗ b / g c d ( a , b ) 等于a * b / gcd(a, b) 等于a∗b/gcd(a,b)
质数
- 完成
判断
- 完成
int pd(int y) {
if(y<2)
return 0;
else if(y==2)
return 1;
for(int i=2; i*i<=y; ++i)
if(y%i==0)
return 0;
return 1;
}
前k个
- 完成
bool isPrime[100000010];
//isPrime[i] == 1表示:i是素数
int Prime[6000010], cnt = 0;
//Prime存质数
void GetPrime(int n)//筛到n
{
memset(isPrime, 1, sizeof(isPrime));
//以“每个数都是素数”为初始状态,逐个删去
isPrime[1] = 0;//1不是素数
for(int i = 2; i <= n; i++)
{
if(isPrime[i])//没筛掉
Prime[++cnt] = i; //i成为下一个素数
for(int j = 1; j <= cnt && i*Prime[j] <= n/*不超上限*/; j++)
{
//从Prime[1],即最小质数2开始,逐个枚举已知的质数,并期望Prime[j]是(i*Prime[j])的最小质因数
//当然,i肯定比Prime[j]大,因为Prime[j]是在i之前得出的
isPrime[i*Prime[j]] = 0;
if(i % Prime[j] == 0)//i中也含有Prime[j]这个因子
break; //重要步骤。见原理
}
}
}
快速幂
- 完成
//a ^ b % p = res
long long res = 1;
for (; b; a = a * a % p, b >>= 1, num++)
if (b & 1)
res = res * a % p;
数据结构
- 完成
链表
- 完成
#include<bits/stdc++.h>
using namespace std;
struct Node{
int value;
Node* next;
//Node *right;
};
void insertNode(int i, Node *p){//插入
Node* node = new Node;
node->value = i;
node->next = p->next;
p->next = node;
}
void deleteNode(Node *p){//删除
p->value = p->next->value;
Node *t = p->next;
p->next = p->next->next;
delete t;
}
int main(){
return 0;
}
STL
- 完成
vector<int> v;
vector<int> ve[12];
v[3]
ve[12][4]
v.push_back(x);
ve[4].push_back(x);
- 完成
队列
- 完成
手写
- 完成
int head = 1, tail = 0, q[N]; // 队头, 队尾, 元素
head++; // 弹出队头
q[++tail] = x; // 将x 入队
q[head] q[tail] // 取队头队尾
head <= tail // 判断队列是否非空
STL
- 完成
queue<int> q; // 定义i n t 类型队列
q.front() // 取队头
q.pop(); // 弹出队头
q.push(x); // 将x 入队
q.empty() // 队列是否为空
单调队列
- 完成
// 入队
for(int i=1;i<=n;i++) {
while(head <= tail && a[q[tail]] > a[i])
tail−−;
while(head <= tail && q[head] <= i − k)
head++;
q[++tail] = i;
// 此时a[q[head]]即为求的[i−k+1, i]最值。
}
优先队列(堆)
- 完成
STL
- 完成
priority_queue<int> q; // 大根堆(支持访问最大)
priority_queue<int, vector<int>, greater<int>> q; //(小根堆)
// 记不下小根堆其实也可用大根堆, 插入值的相反数, 取出后再变成相反数
q.push(x); // 加入x
q.top(); // 取堆顶,请注意堆空时会直接RE!
q.pop(); // 删除堆顶
q.empty() q.size() // 判空、求大小
手写二叉堆
- 完成
#include<bits/stdc++.h>
using namespace std;
const int N = 100004;//结点数
int h[N], n;//树
void up(int x){//向上调整h[x]
while (x > 1 && h[x] > h[x / 2]){
swap(h[x], h[x / 2]);
x /= 2;
}
}
void down(int x){//向下调整h[x]
while (x * 2 <= n){
t = x * 2;
if(t + 1 <= n && h[t + 1] > h[t])
t++;
if (h[t] <= h[x])
break;
swap(h[x], h[t]);
x = t;
}
}
int main(){
return 0;
}
双端队列
- 完成
//注:可用list替换,且占空间更小
deque<int> q; // 定义i n t 类型队列
q.front() // 取队头
q.pop_front(); // 弹出队头
q.pop_back(); // 弹出队尾
q.push_front(x); // 将x 从队头入队
q.push_back(x); // 将x 从队尾入队
q.empty() // 队列是否为空
栈
- 完成
手写
- 完成
int s[N], top ;
// 入栈
s[++top] = x ;
// 出栈
top−−;
// 取栈顶
s[top]
// 判断是否空
(top == 0)
STL
- 完成
// 定义栈s
stack<int> s;
// 加入x
s.push(x);
// 删除
s.pop();
// 取栈顶
s.top()
// 判断空
s.empty()
单调栈
- 完成
// 入栈
for(int i=1;i<=n;i++){
while(a[s[top]] <= a[i] && top)
top−−;
if(top)
f[i] = s[top];
else
f[i] = 0;
s[++top] = i;
}
映射(map)
- 完成
map<string, int> m;
m["qwq"] = 4;
map<int, map<int, int> > a;//二维映射
a[4][12] = 1314;
集合(set)
- 完成
动态规划(DP)
- 完成
背包
- 完成
01背包
- 完成
不超过
- 完成
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n;//物品数量
int w[n+4], v[n+4];//w :重量 v :价值
for(int i=1; i<=n; i++) cin >> w[i] >> v[i];
int W;
cin >> W;//背包容量
int dp[W+4];
memset(dp, 0, sizeof(dp));
for(int i=1; i<=n; i++)
for(int j=W; j>=w[i]; j--)
dp[j] = max(dp[j], dp[j-w[i]] + v[i]);
cout << dp[W];
return 0;
}
正好装满
- 完成
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n;//物品数量
int w[n+4], v[n+4];//w :重量 v :价值
for(int i=1; i<=n; i++) cin >> w[i] >> v[i];
int W;
cin >> W;//背包容量
//注意初始化
memset(dp, -127, sizeof(dp));
dp[0] = 0;
for(int i=1; i<=n; i++)
for(int j=W; j>=w[i]; j--)
dp[j] = max(dp[j], dp[j-w[i]] + v[i]);
cout << dp[W];
return 0;
}
完全背包
- 完成
不超过
- 完成
#include<bits/stdc++.h>
using namespace std;
int dp[204];
int w[32], v[32];
int N, W;
int main(){
cin>>W>>N;
for(int i=1;i<=N;i++)cin>>w[i]>>v[i];
memset(dp, 0, sizeof(dp));
for(int i=1;i<=N;i++)
for(int j=w[i];j<=W;j++)
dp[j] = max(dp[j], dp[j-w[i]]+v[i]);
cout << dp[W];
return 0;
}
正好装满
- 完成
#include<bits/stdc++.h>
using namespace std;
int dp[204];
int w[32], v[32];
int N, W;
int main(){
cin>>W>>N;
for(int i=1;i<=N;i++)cin>>w[i]>>v[i];
//注意初始化
memset(dp, -127, sizeof(dp));
dp[0] = 0;
for(int i=1;i<=N;i++)
for(int j=w[i];j<=W;j++)
dp[j] = max(dp[j], dp[j-w[i]]+v[i]);
cout << dp[W];
return 0;
}
多重背包
- 完成
#include<bits/stdc++.h>
using namespace std;
int main(){
int n, W;
cin >> n >> W;
int w, v, s, ww[10004], vv[10004], cnt = 0, dp[W+4];
memset(dp, 0, sizeof(dp));
//输入+初始化
for(int i=1;i<=n;i++){
cin >> w >> v >> s;
for(int j=1;j<=s;j <<= 1){
ww[++cnt] = w * j;
vv[cnt] = v * j;
s -= j;
}
if(s){
ww[++cnt] = w * s;
vv[cnt] = v * s;
}
}
//用01背包
for(int i=1;i<=cnt;i++)
for(int j=W;j>=1;j--)
if(j >= ww[i])
dp[j] = max(dp[j], dp[j-ww[i]] + vv[i]);
//输出
cout << dp[W];
return 0;
}
树形背包
- 完成
树形DP
- 完成
区间DP
- 完成
数位DP
- 完成
状压DP
- 完成
排序
- 完成
自带:快排
- 完成
bool cmp(int x, int y){
return x > y;
}
int main(){
int n[10000];
sort(n, n+10000);//从小到大
sort(n, n+10000, cmp);//自己写,这里从大到小
return 0;
}
冒泡排序
- 完成
O ( n 2 ) O(n^2) O(n2)
#include<bits/stdc++.h>
using namespace std;
int num[10000];
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
int n;
cin >> n;
for(int i=1;i<=n;i++)
cin >> num[i];
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
if(num[i] > num[j])
swap(num[i], num[j]);
for(int i=1;i<=n;i++)
cout << num[i] << " ";
return 0;
}
选择排序
- 完成
O ( n 2 ) O(n^2) O(n2)
#include<bits/stdc++.h>
using namespace std;
int num[10000];
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
int n;
cin >> n;
for(int i=1;i<=n;i++)
cin >> num[i];
int minn, id;
for(int i=1;i<n;i++){
minn = 1000000000;
for(int j=i;j<=n;j++)
if(num[j] < minn){
minn = num[j];
id = j;
}
swap(num[i], num[id]);
}
for(int i=1;i<=n;i++)
cout << num[i] << " ";
return 0;
}
快速排序
- 完成
O ( n l o g n ) O(n log n) O(nlogn)
#include<bits/stdc++.h>
using namespace std;
int num[1000000];
void qsort(int l, int r){
if(l >= r)
return;
int i = l, j = r, key = num[(i + j) / 2];
while(i <= j){
while(num[i] < key)
i++;
while(num[j] > key)
j--;
if(i <= j)
swap(num[i++], num[j--]);
}
if(l < j)
qsort(l, j);
if(r > i)
qsort(i, r);
return;
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
int n;
cin >> n;
for(int i=1;i<=n;i++)
cin >> num[i];
qsort(1, n);
for(int i=1;i<=n;i++)
cout << num[i] << " ";
return 0;
}
归并排序
- 完成
O ( n l o g n ) O(n log n) O(nlogn)
#include<bits/stdc++.h>
using namespace std;
int num[100004];
void mergeSort(int left, int right){
if(left == right)
return;
else{
int mid = (left + right) / 2;
mergeSort(left, mid);
mergeSort(mid + 1, right);
int left_size = mid - left + 1;
int right_size = right - mid;
int left_num[100004], right_num[100004];
for(int i=left;i<=mid;i++)
left_num[i - left + 1] = num[i];
for(int i=mid+1;i<=right;i++)
right_num[i - mid] = num[i];
int i = 1, j = 1, k = left;
while(i <= left_size && j <= right_size)
if(left_num[i] < right_num[j])
num[k++] = left_num[i++];
else
num[k++] = right_num[j++];
while(i <= left_size)
num[k++] = left_num[i++];
while(j <= right_size)
num[k++] = right_num[j++];
}
}
int main(){
int n;
cin >> n;
for(int i=1;i<=n;i++)
cin >> num[i];
mergeSort(1, n);
for(int i=1;i<=n;i++)
cout << num[i] << " ";
return 0;
}
树
- 完成

建树
- 完成
#include<bits/stdc++.h>
using namespace std;
struct node{
char data;
int Left,Right;
}a[N];
int main(){
cin>>n;
char x,y,z;
int root=0; // 记录根节点
for (int i=1;i<=n;i++){
cin >> x >> y >> z;
if (!root)
root = x-'a'+1;
int t = x-'a'+1;
a[t].data = x;
if (y>='a' && y<='z')
a[t].Left=y-'a'+1;
if (z>='a' && z<='z')
a[t].Right=z-'a'+1;
}
return 0;
}
遍历
- 完成
先序
- 完成
void pre_order(int root){
// 先序遍历:根左右
if (root==0) return ;
cout<<a[root].data<<" ";
pre_order(a[root].Left);
pre_order(a[root].Right);
}
中序
- 完成
void in_order(int root){
// 中序遍历:左根右
if (root==0) return ;
in_order(a[root].Left);
cout<<a[root].data<<" ";
in_order(a[root].Right);
}
后序
- 完成
void post_order(int root){
// 后序遍历:左右根
if (root==0) return ;
post_order(a[root].Left);
post_order(a[root].Right);
cout<<a[root].data<<" ";
}
LCA
- 完成
二叉搜索树
- 完成
//完整注释版 二叉搜索树
//本质:对于根节点,小的扔左边,大的扔右边
#include<bits/stdc++.h>
using namespace std;
#define ls tree[x].son[0]
#define rs tree[x].son[1]
const int N = 10010;
const int INF = 0x7fffffff;
//inline int read(){//快读
// int r = 0; bool w = 0; char ch = getchar();
// while(ch < '0' || ch > '9')
// w = ch == '-' ? 1 : w, ch = getchar();
// while(ch >= '0' && ch <= '9')
// r = (r << 3) + (r << 1) + (ch ^ 48), ch =
// getchar();
// return w ? ~r + 1 : r;
//}
//左小右大!!!! 从小到大!!!!
struct Node{//一个节点:值,子树节点数,相等值计数,左右儿子下标
int val, siz, cnt, son[2];
}tree[N];
int n, root, tot;//询问个数,根下标,节点个数
void add(int v){//插入
if(!tot){//根节点
root = ++tot;
tree[tot].cnt = tree[tot].siz = 1;//cnt,siz初始都为1,初始化1
tree[tot].son[0] = tree[tot].son[1] = 0;//初始化2
tree[tot].val = v;//初始化3
return;
}
int x = root, last = 0;//x:正在比的;last:父节点
while(1){
++tree[x].siz;//子树节点数+1
if(tree[x].val == v){//与当前结点值相等
++tree[x].cnt;//相等值计数+1
break;//就做完了
}
last = x;//下一层
x = tree[last].son[v > tree[last].val];//无子节点:x=0
if(!x){//如果没有子节点
//v > tree[last].val:大,1,右子树;小,0,左子树
tree[last].son[v > tree[last].val] = ++tot;//连到父节点
tree[tot].cnt = tree[tot].siz = 1;//初始化1
tree[tot].son[0] = tree[tot].son[1] = 0;//初始化2
tree[tot].val = v;//初始化3
break;
}
}
}
int queryfr(int val){//求前驱(前驱定义为小于val,且最大的数)
int x = root, ans = -INF;//没有:-INF
while(1){
if(x == 0)//找到底了
return ans;//返回答案
if(tree[x].val >= val){//x的值比val大(不可能在右子树里)
if(ls == 0)//没有左子树
return ans;
x = ls;//找左子树(即更小的)
}
else{//x值比它小(不在左子树里,右子树更大,所以更优)
if(rs == 0)//没有右子树
return tree[x].val;//因为x比val小,所以返回
ans = tree[x].val;//更新答案
x = rs;//找右子树(更大、更优)
}
}
}
int queryne(int v){//求后继(后继定义为大于v,且最小的数)
int x = root, ans = INF;//没有:INF
while(1){
if(x == 0)//找到底了
return ans;//返回答案
if(tree[x].val <= v){//x的值比v小(不可能在左子树里)
if(rs == 0)//没有右子树
return ans;
x = rs;//找右子树(即更大的)
}
else{//x值比它大(不在右子树里,左子树更小,所以更优)
if(ls == 0)//没有左子树
return tree[x].val;//因为x比v大,所以返回
ans = tree[x].val;//更新答案
x = ls;//找左子树(更大、更优)
}
}
}
int queryrk(int rk){//求排名为rk的
int x = root;
while(1){
if(x == 0)//找完了还没找到
return INF;
if(tree[ls].siz >= rk)//排名从小到大,左子树都比X结点小,
x = ls; //总结点数>rk,在左子树内
else if(tree[ls].siz + tree[x].cnt >= rk)//左子树不够,但加
return tree[x].val;//x的数量够,返回x
else{//还不够:右子树大,剩下的在右子树内
rk -= tree[ls].siz + tree[x].cnt;
x = rs;
}
}
}
int queryval(int v){//求比当前数小的数的个数,(x数的排名-1)
int x = root, ans = 0;//ans是上方比v小的数量
while(1){
if(x == 0)//找到底了
return ans;//返回
if(tree[x].val == v)//当前结点是v,返回ans+左子树(左子树小)
return ans + tree[ls].siz;
else if(tree[x].val > v)//比v大
x = ls;//在左子树里找
else{//比v小
ans += tree[ls].siz + tree[x].cnt;//加上左子树
x = rs;//在右子树里找
}
}
}
int main(){
cin >> n;
while(n--){
int opt, x;
cin >> opt >> x;
if(opt == 1)
printf("%d\n", queryval(x) + 1);
if(opt == 2)
printf("%d\n", queryrk(x));
if(opt == 3)
printf("%d\n", queryfr(x));
if(opt == 4)
printf("%d\n", queryne(x));
if(opt == 5)
add(x);
}
return 0;
}
并查集
- 完成
//并查集
//并查集性质:并查集产生的每一个集合都是一棵树
#include<bits/stdc++.h>
using namespace std;
//初始化
/*
for (int i=1;i<=n;i++)
fa[i]=i;
*/
//查找
/*
1.朴素
(1)递推
int Find(int x){
while(x!=fa[x])
x=fa[x];
return x;
}
(2)递归
int Find(int x){
if(x==fa[x])
return x;
return Find(fa[x]);
}
2.优化
// 寻找根节点的路径压缩(递归写法)
int Find(int x){
if (x==fa[x])
return x;
return fa[x]=Find(fa[x]);
// 递归过程查找根节点,同时把根节点赋值给fa[x]
}
*/
//合并
/*
void Union(int a,int b){
int faA=Find(a); // 查找a的根节点,记为faA
int faB=Find(b); // 查找b的根节点,记为faB
if (faA!=faB)
Find(faA)=faB; // 合并
}
*/
//以下题目为 洛谷 P1551 亲戚
#include<bits/stdc++.h>
using namespace std;
const int N=5010;
int n,m,t;
int f[N]; // 点与父结点
int Find(int x){
// 查找与修改当前点的父结点为根节点
if (x != f[x])
return f[x] = Find(f[x]);// 如果当前父结点不是根结
//点,则递归查找
return x; // 返回根节点
}
int main(){
cin >> n >> m >> t;
for (int i=1;i<=n;i++)
f[i] = i; // 初始化父结点为自己
int x, y; // 表示关系链
for (int i=1;i<=m;i++){
cin >> x >> y; // 输入关系 1 2
f[Find(x)] = Find(y); // 查询并合并两点,将左图中的根节
//点5合并到右图结点5(原来父结点是自己)的父结点修改为4
// for (int i=1;i<=n;i++) cout<<f[i]<<" " ;可以查看过程
}
for (int i=1;i<=t;i++){
cin >> x >> y; //检查两者是否有关系,即是否在一个集合
f[x] = Find(x);
f[y] = Find(y); // 查找两点的根节点
if (f[x] == f[y])
cout << "Yes" << endl; // 如果根节点一样,则在同一个集合
else
cout << "No" << endl;
}
return 0;
}
快读
- 完成
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
inline int read(){
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
高精度
- 完成
#include<bits/stdc++.h>
using namespace std;
const int N = 3000;
int x[N], y[N];
int c[N];
string a, b;
int num;
void mults(){
num = a.size() + b.size() - 1;
for(int i=0;i<num;i++){
for(int j=0;j<=i;j++)
c[i] += x[j] * y[i-j];
if(c[i] >= 10){
c[i + 1] += c[i] / 10;
c[i] %= 10;
}
}
//去掉多余的前导零
for(int i=num;i>0;i--)
if(c[i] == 0)
num--;
else
break;
}
int main(){
cin >> a >> b;
memset(x, 0, sizeof(x));
memset(y, 0, sizeof(y));
for(int i =a.size()-1;i>=0;i--)
x[a.size() - 1 - i] = a[i] -'0';
for(int i= b.size()-1;i>=0;i--)
y[b.size() - 1 - i] = b[i] -'0';
mults();
for(int i=num;i>=0;i--)
printf("%d", c[i]);
return 0;
}
17





