各种模板汇总

前言

存一些自己以前写的模板,方便自己找(PS:不断更新,有点懒,想到啥更新啥)



一、数学

1. 二分

见文章

2. 快速幂

long long ksm(long long a, long long n, long long mod) {
	long long ans = 1;
	while(n) {
		if(n & 1)
			ans = (ans * a) % mod;
		a = (a * a) % mod;
		n >>= 1;
	}
	return ans % mod;
}

3. 筛素数

(1) 埃氏筛

//初始化都是素数
bool numlist[100000000];
int prime[2000001], cnt;
for(int i = 2; i <= N; ++i) {
	if(numlist[i] == false){
		prime[++cnt] = i ;
    	for(int j = i; i * j <= N; ++j) { 
			numlist[i * j] = true;  // 不是素数标记 1
    	}
    }
}

(2) 欧拉筛

#include <cstdio>
#include <cstring>
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; //重要步骤。见原理
		}
	}
}
int main()
{
	int n, q;
	scanf("%d %d", &n, &q);
	GetPrime(n);
	while (q--)
	{
		int k;
		scanf("%d", &k);
		printf("%d\n", Prime[k]);
	}
	return 0;
}

二、最短路

1. floyd

void flody(){
	for(int k = 0; k < n; ++k)
		for(int i = 0; i < n; ++i)
			for(int j = 0; j < n; ++j)
				map[i][j] = min(map[i][j], map[i][k] + map[k][j]);
}

2. dijkstra(朴素版)

注意每个数组的初始化问题

(1) 核心代码

void dijkstra(int s){
	memset(dis, inf, sizeof dis);
	dis[s] = 0;
	for(int i = 0; i < n; ++i){
		int t = -1;
		for(int j = 0; j < n; ++j)
			if(!vis[j] && (t == -1 || dis[j] < dis[t]))
				t = j;
		vis[t] = 1;
		for(int j = 0; j < n; ++j)
			dis[j] = min(dis[j], dis[t] + map[t][j]);
	}
}

(2) 多重判断 + 输出路径

#include <iostream>
#include <cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
int map[550][550], vis[550], dis[550], path[550];
int a[550][550], sum[550];
int n, m, S, D;
void dijkstra(int s){
	memset(dis, inf, sizeof dis);
	dis[s] = 0;
	for(int i = 0; i < n; ++i){
		int t = -1;
		for(int j = 0; j < n; ++j)
			if(!vis[j] && (t == -1 || dis[j] < dis[t]))
				t = j;
		vis[t] = 1;
		for(int j = 0; j < n; ++j){
			if(dis[j] > dis[t] + map[t][j]){
				dis[j] = dis[t] + map[t][j]; //更新最短距离
				sum[j] = sum[t] + a[t][j];   //更新相应值
				path[j] = t;       //存路径
			}
			else if(dis[j] == dis[t] + map[t][j]){
				if(sum[j] > sum[t] + a[t][j]){
					sum[j] = sum[t] + a[t][j];
					path[j] = t;
				}
			}
		}
	}
}
void dfs(int x){  //输出路径,注意是从后往前找
	if(x == S){
		printf("%d", x);
		return;
	}
	dfs(path[x]);
	printf(" %d", x);
}
int main() {
	cin >> n >> m >> S >> D;
	memset(map, inf, sizeof map);
	for(int i = 0; i < n; ++i)
		map[i][i] = 0;
	while(m--){
		int x, y, z1, z2;
		cin >> x >> y >> z1 >> z2;
		map[x][y] = map[y][x] = z1;
		a[x][y] = a[y][x] = z2;
	}
	dijkstra(S);
	dfs(D);
	printf(" %d %d", dis[D], sum[D]);
} 

3. spfa

解决负权边问题

#include <iostream>
#include <cstring>
#include <queue> 
using namespace std;
const int inf = 0x3f3f3f3f, N = 2e5 + 10;
int e[N], w[N], ne[N], h[N], vis[N], dis[N], ret, n, m;
void add(int a, int b, int c) {
	e[ret] = b;
	w[ret] = c;
	ne[ret] = h[a];
	h[a] = ret++;
} 
void spfa(int s) {
	memset(dis, inf, sizeof dis);
	dis[s] = 0;
	queue<int> q;
	q.push(s);
	vis[s] = 1;
	while(!q.empty()) {
		int t = q.front();
		q.pop();
		vis[t] = 0;
		for(int i = h[t]; i != -1; i = ne[i]){
			int j = e[i];
			if(dis[j] > dis[t] + w[i]){
				dis[j] = dis[t] + w[i];
				if(!vis[j]) {
					q.push(j);
					vis[j] = 1;
				}
			}
		}
	}
}
int main() {
	memset(h, -1, sizeof h);
	cin >> n >> m;
	while(m--) {
		int x, y, z;
		cin >> x >> y >> z;
		add(x, y, z);
	}
	spfa(1);
	for(int i = 2; i <= n; ++i)
		cout << dis[i] << endl;
} 

4. 最小生成树

#include <iostream>
#include <cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
int map[1010][1010], vis[1010], dis[1010], n, m;
int prim() {
	memset(dis, inf, sizeof dis);
	int sum = 0;
	for(int i = 0; i < n; ++i) {
		int t = -1;
		for(int j = 1; j <= n; ++j) 
			if(!vis[j] && (t == -1 || dis[j] < dis[t]))
				t = j;
		vis[t] = 1;
		if(i && dis[t] == inf)
			return inf;
		if(i)
			sum += dis[t];
		for(int j = 1; j <= n; ++j)
			dis[j] = min(dis[j], map[t][j]);
	}
	return sum;
}
int main() {
	memset(map, inf, sizeof map);
	cin >> n >> m;
	for(int i = 1; i <= n; ++i)
		map[i][i] = 0;
	while(m--) {
		int x, y, z;
		cin >> x >> y >> z;
		map[x][y] = map[y][x] = min(map[x][y], z);
	}
	int sum = prim();
	if(sum == inf) cout << -1;
	else  cout << sum;
}

三、搜索

1. dfs(深度优先搜素)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char a[520][520];
int vis[520][520];
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
int f, ex, ey, n, m, sx, sy;
void dfs(int x,int y) {
	if(x == ex && y == ey){ 
		f = 1; return; 
	} 
	for(int i = 0; i < 4; ++i) {
		int xx = x + dir[i][0];
		int yy = y + dir[i][1];
		if(vis[xx][yy] == 1 || a[xx][yy]=='#' || xx < 0 || xx >= n || yy < 0 || yy >= m)
			continue;
		vis[xx][yy] = 1;
		dfs(xx, yy);
		//vis[xx][yy]=0;
	}
} 
int main() {
	while(cin >> n >> m) {
        memset(vis, 0, sizeof vis);
		f = 0;
		for(int i = 0; i < n; ++i)
			scanf("%s", a[i]);
		for(int i = 0; i < n; ++i) {
			for(int j = 0; j < m; ++j) {
				if(a[i][j] == 'S') 
					sx = i, sy = j;
				if(a[i][j] == 'E')
					ex = i, ey = j;
			}
		}
		dfs(sx, sy);
		if(f) printf("Yes\n");
		else printf("No\n");
	}
}

2. bfs(广度优先搜索)

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
char a[550][550];
int vis[550][550], n, m, sx, sy, ex, ey;
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
struct node{
	int x, y;
};
int bfs(int x, int y) {
	int f = 0;
	queue<node> q;
	q.push({x, y});
	vis[x][y] = 1;
	while(!q.empty()) {
		node t = q.front(); q.pop();
		if(t.x == ex && t.y == ey){
			f = 1;break;
		}
		for(int i = 0; i < 4; ++i){
			int xx = t.x + dir[i][0];
			int yy = t.y + dir[i][1];
			if(a[xx][yy] == 'x' || vis[xx][yy] || xx < 0 || xx >= n || yy < 0 || yy >= m)
				continue;
			vis[xx][yy] = 1;
			q.push({xx, yy});
		}
	}
	return f;
}
int main() {
    int t;
    cin >> t;
	while(t--) {
        cin >> n >> m;
		memset(vis, 0, sizeof vis);
		for(int i = 0; i < n; ++i) {
			for(int j = 0; j < m; ++j) {
				cin >> a[i][j];
				if(a[i][j] == 's'){
					sx = i, sy = j;
				}
				if(a[i][j] == 't'){
					ex = i, ey = j;
				}
			}
		}
		if(bfs(sx, sy)) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
}

四、并查集

1. 基本用法

#include<iostream>
using namespace std;
int fa[50500];
int find(int x) {
	if(fa[x] == x) 
		return x;
	else 
		return fa[x]=find(fa[x]);
}
int main() {
	int n, m, p, x, y;
	scanf("%d%d%d", &n, &m, &p);
	for(int i = 1; i <= n; ++i) //初始化每个点 
		fa[i] = i;
	while(m--) {
		scanf("%d%d", &x, &y);
		fa[find(x)] = find(y);
	}
	while(p--) {
		scanf("%d%d", &x, &y);
		if(find(x) == find(y))
			printf("Yes\n");
		else
			printf("No\n");
	}
	return 0;
}

2. 路径压缩的应用

#include <iostream>
#include <map>
using namespace std;
map<string, string> fa;
map<string, int> weight, ret, sum, ans;
string find(string x){
	string y = x;
	while(x != fa[x]) x = fa[x];
	if(weight[y] > weight[x]){
		fa[x] = y;
		fa[y] = y;
		return y;
	}
	return x;
}
int main() {
	int n, k, x;
	cin >> n >> k;
	while(n--){
		string a, b;
		cin >> a >> b >> x;
		if(fa[a] == "") fa[a] = a;
		if(fa[b] == "") fa[b] = b;
		weight[a] += x, weight[b] += x;
		if(weight[find(a)] > weight[find(b)])
			fa[find(b)] = find(a);
		else
			fa[find(a)] = find(b);
	}
	for(auto it = fa.begin(); it != fa.end(); ++it){
		ret[find(it->first)]++;
		sum[find(it->first)] += weight[it->first];
	}
	for(auto it = ret.begin(); it != ret.end(); ++it)
		if(sum[it->first] / 2 > k && it->second > 2)
			ans.insert(*it);
	cout << ans.size() << endl;
	for(auto it = ans.begin(); it != ans.end(); ++it)
		cout << it->first << " " << it->second << endl;
} 

五、图论

1. AVL(平衡二叉搜索树)

#include <iostream>
using namespace std;
struct node{
	int val;
	struct node *left, *right;
};
node *rotateLeft(node *root) {
	node *t = root->right;
	root->right = t->left;
	t->left = root;
	return t;
}
node *rotateRight(node *root) {
	node *t = root->left;
	root->left = t->right;
	t->right = root;
	return t;
}
node *rotateLeftRight(node *root) {
	root->left = rotateLeft(root->left);
	return rotateRight(root);
}
node *rotateRightLeft(node *root) {
	root->right = rotateRight(root->right);
	return rotateLeft(root);
}
int height(node *root) {
	if(root == NULL) return 0;
	return max(height(root->left), height(root->right)) + 1;
}
node *insert(node *root, int v) {
	if(root == NULL) {
		root = new node();
		root->val = v;
		root->left = root->right = NULL;
	} else if(v < root->val){
		root->left = insert(root->left, v);
		if(height(root->left) - height(root->right) > 1)
			root = v < root->left->val ? rotateRight(root) : rotateLeftRight(root);
	} else{
		root->right = insert(root->right, v);
		if(height(root->left) - height(root->right) < -1)
			root = v > root->right->val ? rotateLeft(root) : rotateRightLeft(root);
	}
	return root;
}
int main() {
	int n, x;
	cin >> n;
	node *root = NULL;
	for(int i = 0; i < n; ++i){
		cin >> x;
		root = insert(root, x);
	}
	cout << root->val;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值