算法学习1

1 快速排序

#include<iostream>
#pragma warning(disable:4996)
using namespace std; 
//快速排序
const int N = 1e6 + 10;
int n;
int q[N];
void quick_sort(int q[], int l, int r)
{
	if (l >= r) return;
	int x = q[l], i = l - 1, j = r + 1;
	while (i<j)
	{
		do i++; while (q[i] < x);
		do j--; while (q[j] > x);
		if (i < j)swap(q[i], q[j]);
	}
	quick_sort(q, l, j);
	quick_sort(q, j + 1, r);
}
int main()
{
	scanf("%d", &n);
	for (int i = 0; i < n; i++) scanf("%d", &q[i]);
	quick_sort(q, 0, n - 1);
	for (int i = 0; i < n; i++) printf("%d", q[i]);
	return 0}

2 归并排序

#include<iostream>
#pragma warning(disable:4996)
using namespace std; 
//归并排序
const int N = 1000010;
int n;
int q[N], tmp[N];
void merge_sort(int q[], int l, int r) {
  if(l>=r)return;
	int mid = l + r >> 1;
	merge_sort(q, l, mid), merge_sort(q, mid + 1, r);
	int k = 0, i = l, j = mid+1;
	while (i <= mid && j <=r) {
		if (q[i] < q[j])tmp[k++] = q[i++];
		else tmp[k++] = q[j++];
	}
	while (i <= mid) tmp[k++] = q[i++];
	while (j <= r) tmp[k++] = q[j++];
	for (i = l, j = 0; i <= r; i++, j++) q[i] = tmp[j];
}
int main()
{
	scanf("%d", &n);
	for (int i = 0; i < n; i++) scanf("%d", &q[i]);
	merge_sort(q, 0, n - 1);
	for (int i = 0; i < n; i++) printf("%d", q[i]);
	return 0}

3 二分查找

#include<iostream>
#pragma warning(disable:4996)
using namespace std; 
//二分查找
const int N = 100010;
int n, m;
int q[N];
int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 0; i < n; i++) scanf("%d", &q[i]);
	while (m--)
	{
		int x;
		scanf("%d", &x);
		int l = 0, r = n - 1;
		while (l < r)
		{
			int mid = l + r >> 1;
			if (q[mid] >= x)r = mid;
			else l = mid + 1;
		}
		if (q[l] != x) cout << "-1 -1" << endl;
		else
		{
			cout << l << ' ';
			int l = 0, r = n - 1;
			while (l<r)
			{
				int mid = l + r + 1 >> 1;
				if (q[mid] <= x)l = mid;
				else r = mid - 1;
			}
			cout << l << endl;
		}
	}

	return 0;
}

4 高精度加法

#include<iostream>
#pragma warning(disable:4996)
using namespace std; 
#include<vector>

const int N = 1E6 + 10;
// C=A+B
vector<int> add(vector<int>& A, vector<int>& B)
{
	vector<int>C;
	int t = 0;//进位
	for (int i = 0; i < A.size() || i < B.size(); i++)
	{
		if (i < A.size()) t += A[i];
		if (i < B.size())t += B[i];
		C.push_back(t % 10);
		t /= 10;
	}
	if (t) C.push_back(1);
	return C;
}
int main()
{
	string a, b;
	vector<int> A, B;
	cin >> a >> b; // a="123456"
	for (int i = a.size() - 1; i >= 0; i--)A.push_back(a[i] - '0'); //A=[6,5,4,3,2,1]
	for (int i = b.size() - 1; i >= 0; i--)B.push_back(b[i] - '0');
	auto C = add(A, B);

	for (int i = C.size() - 1; i >= 0; i--)printf("%d", C[i]);
	return 0;
}

5 高精度减法

#include<iostream>
#pragma warning(disable:4996)
using namespace std; 
#include<vector>

//判断是否有A>=B
bool cmp(vector<int>& A, vector<int>& B)
{
	if (A.size() != B.size()) return A.size() >= B.size();
	for (int i = A.size() - 1; i >= 0; i--)
		if (A[i] != B[i])
			return A[i] > B[i];
	return true;
}
// C=A-B
vector<int> sub(vector<int>& A, vector<int>& B)
{
	vector<int>C;
	for (int i = 0, t = 0; i < A.size(); i++)
	{
		t = A[i] - t;
		if (i < B.size()) t -= B[i];
		C.push_back((t + 10) % 10);
		if (t < 0)t = 1;
		else t = 0;
	}
	while (C.size() > 1 && C.back() == 0) C.pop_back(); //去掉前导零
	return C;
}
int main()
{
	string a, b;
	vector<int> A, B;
	cin >> a >> b; // a="123456"
	for (int i = a.size() - 1; i >= 0; i--)A.push_back(a[i] - '0'); //A=[6,5,4,3,2,1]
	for (int i = b.size() - 1; i >= 0; i--)B.push_back(b[i] - '0');
	
	if (cmp(A, B))
	{
		auto C = sub(A, B);
		for (int i = C.size() - 1; i >= 0; i--)printf("%d", C[i]);
	}
	else
	{
		auto C = sub(B, A);
		printf("-");
		for (int i = C.size() - 1; i >= 0; i--)printf("%d", C[i]);
	}
	
	return 0;
}

6 高精度乘法

#include<iostream>
#pragma warning(disable:4996)
using namespace std; 
#include<vector>

vector<int>mul(vector<int>& A, int b)
{
	vector<int>C;
	int t = 0;//进位
	for (int i = 0; i < A.size() || t; i++)
	{
		if (i < A.size()) t += A[i] * b;
		C.push_back(t % 10);
		t /= 10;
	}
	return C;
}
int main()
{
	string a;
	int b;
	cin >> a >> b;
	vector<int>A;
	for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');
	auto C = mul(A, b);
	for (int i = C.size() - 1; i >= 0; i--)printf("%d", C[i]);
	
	
	return 0;
}

7 高精度除法

#include<iostream>
#pragma warning(disable:4996)
using namespace std; 
#include<vector>

// A/b 商是C,余数是r
vector<int>div(vector<int>& A, int b,int &r)
{
	vector<int>C;
	r = 0;
	for (int i = A.size() - 1; i >= 0; i--)
	{
		r = r * 10 + A[i];
		C.push_back(r / b);
		r %= b;
	}
	reverse(C.begin(), C.end());
	while (C.size() > 1 && C.back() == 0) C.pop_back();
	
	return C;
}
int main()
{
	string a;
	int b;
	cin >> a >> b;
	vector<int>A;
	for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');
	int r;
	auto C = div(A, b,r);
	for (int i = C.size() - 1; i >= 0; i--)printf("%d", C[i]);
	cout << endl << r << endl;
	
	
	return 0;
}

8 前缀和

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>

const int N=100010;
int n, m;
int S[N];

int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) scanf("%d", &S[i]);
	for (int i = 1; i <=n; i++) S[i] += S[i - 1] ;
	while (m--) {
		int l, r;
		scanf("%d%d", &l, &r);
		printf("%d\n", S[r] - S[l - 1]);
	}

	return 0;
}

9 子矩阵的和

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>

const int N=1010;
int n, m,q;
int a[N][N], S[N][N];

int main()
{
	scanf("%d%d%d", &n, &m, &q);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			scanf("%d", &a[i][j]);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			S[i][j] = S[i][j - 1] + S[i - 1][j] - S[i - 1][j - 1] + a[i][j];
	while (q--) {
		int x1, y1,x2,y2;
		scanf("%d%d%d%d", &x1, &y1,&x2,&y2);
		printf("%d\n", S[x2][y2] - S[x2][y1-1] - S[x1-1][y2] + S[x1-1][y1-1]);
	}
	return 0;
}

10 差分

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>

const int N=100010;
int n, m;
int b[N], a[N];

void insert(int l, int r, int c)
{
	b[l] += c;
	b[r + 1] -= c;
}

int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	for (int i = 1; i <= n; i++)
		insert(i, i, a[i]);
	while (m--)
	{
		int l,r,c;
		scanf("%d%d%d",&l,&r,&c);
		insert(l, r, c);
	}
	for (int i = 1; i <= n; i++) b[i] += b[i - 1];
	for (int i = 1; i <= n; i++)printf("%d", b[i]);
	return 0;
}

11 差分矩阵

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>

const int N = 1010;
int n, m;
int a[N][N], b[N][N];

void insert(int x1, int y1, int x2, int y2, int c) {
	b[x1][y1] += c;
	b[x1][y2 + 1] -= c;
	b[x2+1][y1 ] -= c;
	b[x2 + 1][y2 + 1] += c;
}

int main()
{
	int q;
	scanf("%d%d%d", &n, &m, &q);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			scanf("%d", &a[i][j]);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			insert(i, j, i, j, a[i][j]);
	while (q--) {
		int x1, y1, x2,y2,c;
		cin >> x1 >> y1 >> x2 >> y2 >> c;
		insert(x1, y1, x2, y2, c);
	}
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			b[i][j] += b[i - 1][j] + b[i][j-1] - b[i - 1][j - 1];
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++)
			printf("%d", b[i][j]);
		puts(" ");
	}
	return 0;
}

12 最长连续不重复子序列

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>

const int N = 100010;
int a[N], S[N];
int n;

int main()
{
	
	cin >> n;
	for (int i = 0; i < n; i++) cin >> a[i];
	int res = 0;
	for (int i = 0, j = 0; i < n; i++) {
		S[a[i]]++;
		while (S[a[i]] > 1) {
			S[a[j]]--;
			j++;
		}
		res = max(res, i - j + 1);
	}
	cout << res << endl;
	return 0;
}

13 二进制中1的个数

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>

int lowbit(int x)
{
	return x & -x;//-x二进制为~x+1, x=1010,~x=0101,~x=1=0110;
}

int main()
{
	int n;
	cin >> n;
	while (n--) {
		int x;
		cin >> x;
		int res = 0;
		while (x) x -= lowbit(x), res++;//每次减去x的最后一位1

		cout << res << endl;
	}
	return 0;
	
	return 0;
}

14 离散化(区间和)

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
const int N = 300010;
int n, m;
int a[N], s[N];
typedef pair<int, int> PII;
vector<int>alls;
vector<PII>add, query;

int find(int x) {
	int l = 0, r = alls.size() - 1;
	while(l<r){
		int mid = l + r >> 1;
		if (alls[mid] >= x)r = mid;
		else l = mid + 1;
	}
	return r + 1; //离散映射从1开始;
}
int main()
{
	
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		int x, c;
		cin >> x >> c;
		add.push_back({ x, c });
		alls.push_back(x);
	}
	for (int i = 0; i < m; i++) {
		int l, r;
		cin >> l >> r;
		query.push_back({ l, r });
		alls.push_back(l);
		alls.push_back(r);
	}
	//去重
	sort(alls.begin(), alls.end());
	alls.erase(unique(alls.begin(), alls.end()), alls.end());
	//处理插入
	for (auto item : add) {
		int x = find(item.first);
		a[x] += item.second;
	}
	//预处理前缀和
	for (int i = 1; i <= alls.size(); i++)s[i] = s[i - 1] + a[i];
	//处理询问
	for (auto item : query) {
		int l = find(item.first);
		int r = find(item.second);
		cout << s[r] - s[l - 1] << endl;
	}
	return 0;
}

在这里插入图片描述

vector<int>::iterator unique(vector<int>& a) {
	int j = 0;
	for (int i = 0; i < a.size(); i++)
	{
		if (!i || a[i] != a[i - 1])
			a[j++] = a[i];
		//a[0] ~ a[j-1] 所有a中不重复的数
	}
	return a.begin() + j;
}

15 区间合并

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
const int N = 100010;
int n;
typedef pair<int, int> PII;
vector<PII>segs;
void merge(vector<PII>& segs) {
	vector<PII> res;
	int st = -2e9, ed = -2e9;
	for (auto seg : segs) {
		if (ed < seg.first) {
			if (st != -2e9) res.push_back({ st,ed });
			st = seg.first, ed = seg.second;
		}
		else ed = max(ed, seg.second);
	}
	if (st != -2e9)res.push_back({ st,ed });
	segs = res;
}
int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		int l, r;
		cin >> l >> r;
		segs.push_back({ l,r });

	}
	merge(segs);
	cout << segs.size() << endl;
	
	return 0;
}

在这里插入图片描述

16 单链表

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>

const int N = 10010;
//head表示头节点的下标
//e[i]表示节点i的值
//ne[i]表示节点i的next指针是多少
//idx存储当前已经用到了哪个点
int head, e[N], ne[N], idx;
//初始化
void init() {
	head = -1;
	idx = 0;
}
//将x插到头结点
void add_to_head(int x){
	e[idx] = x, ne[idx] = head, head = idx++;
}
//将x插到下标是k的点后面
void add(int k, int x) {
	e[idx] = x, ne[idx] = ne[k], ne[k] = idx++;
}
//将下标是k的点后面的点删掉
void remove(int k) {
	ne[k] = ne[ne[k]];
}
int main()
{
	int m;
	cin >> m;
	init();
	while (m--)
	{
		int k, x;
		char op;
		cin >> op;
		if (op == 'H')
		{
			cin >> x;
			add_to_head(x);
		}
		else if (op == 'D')
		{
			cin >> k;
			if (!k)head = ne[head];
			remove(k - 1);
		}
		else
		{
			cin >> k >> x;
			add(k - 1, x);
		}
	}
	for (int i = head; i != -1; i = ne[i])cout << e[i] << ' ';
	cout << endl;
	return 0;
	
}

在这里插入图片描述

17 双链表

const int N = 100010;

//e[]表示节点的值,l[]表示节点的左指针,r[]表示节点的右指针,idx表示当前用到了哪个节点
int e[N], l[N], r[N], idx;

//初始化
void init()
{
	//0是左端点,1是右端点
	r[0] = 1, l[1] = 0;
	idx = 2;
}
//在节点k的右边插入一个数x
void insert(int k, int x)
{
	e[idx] = x;
	r[idx] = r[k];
	l[idx] = k;
	l[r[k]] = idx;
	r[k] = idx++;
}
//删除节点a
void remove(int k)
{
	r[l[k]] = r[k];
	l[r[k]] = l[k];
}

18 模拟栈

// tt表示栈顶
int stk[N], tt = 0;

// 向栈顶插入一个数
stk[ ++ tt] = x;

// 从栈顶弹出一个数
tt -- ;

// 栈顶的值
stk[tt];

// 判断栈是否为空
if (tt > 0)
{

}

19 循环队列

// hh 表示队头,tt表示队尾的后一个位置
int q[N], hh = 0, tt = 0;

// 向队尾插入一个数
q[tt ++ ] = x;
if (tt == N) tt = 0;

// 从队头弹出一个数
hh ++ ;
if (hh == N) hh = 0;

// 队头的值
q[hh];

// 判断队列是否为空
if (hh != tt)
{

}

20 单调栈

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>

const int N = 100010;
int stk[N], tt;
int main()
{
	int n;
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
	{
		int x;
		scanf("%d", &x);
		while (tt && stk[tt] >= x)tt--;
		if (tt) printf("%d ", stk[tt]);
		else printf("-1 ");
		stk[++tt] = x;
	}



	return 0;
	
}

21 滑动窗口

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>

const int N = 1000010;
int x, k,n;
int a[N], q[N];
int main()
{
	scanf("%d%d", &n, &k);
	for (int i = 0; i < n; i++)scanf("%d", &a[i]);
	int hh = 0, tt = -1;
	for (int i = 0; i < n; i++)
	{
		//判断队头是否已经滑出窗口
		while (tt >= hh && i - k + 1 > q[hh])hh++;
		while (tt >= hh && a[q[tt]] > a[i])tt--;
		q[++tt] = i;
		if(i>=k-1)printf("%d ", a[q[hh]]);
	}
	puts(" ");
	hh = 0, tt = -1;
	for (int i = 0; i < n; i++)
	{
		//判断队头是否已经滑出窗口
		while (tt >= hh && i - k + 1 > q[hh])hh++;
		while (tt >= hh && a[q[tt]] < a[i])tt--;
		q[++tt] = i;
		if(i>=k-1)printf("%d ", a[q[hh]]);
	}

	return 0;
	
}

在这里插入图片描述

22 kmp字符串

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>

const int N = 10010, M = 100010;
int n, m;
char p[N], s[M];
int ne[N];
int main()
{
	cin >> n >> p + 1 >> m >> s + 1;//+1往后移动一位
	//求next的过程
	for (int i = 2, j = 0; i <= n; i++)
	{
		while (j && p[i] != p[j + 1]) j = ne[j];
		if (p[i] == p[j + 1])j++;
		ne[i] = j;
	}
	//kmp匹配过程
	for (int i = 1, j = 0; i <= m; i++)
	{
		while (j && s[i] != p[j + 1])j = ne[j];
		if (s[i] == p[j + 1])j++;
		if(j==n)
		{
			printf("%d ", i - n);//题目要求从零开始
			j = ne[j];
		}
	}
	return 0;
	
}

在这里插入图片描述

23 Trie字符串统计

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>

const int N = 100010;

int son[N][26], cnt[N], idx;
char str[N];
//0号点既是根节点,又是空节点
//son[][]存储树中每个节点的子节点
//cnt[]存储以每个节点结尾的单词数量

void insert(char *str)
{
	int p = 0;
	for (int i = 0; str[i]; i++) {
		int u = str[i] - 'a';
		if (!son[p][u])son[p][u]=++idx;
		p = son[p][u];
	}
	cnt[p]++;
}
int query(char* str)
{
	int p = 0;
	for (int i = 0; str[i]; i++)
	{
		int u = str[i] - 'a';
		if (!son[p][u]) return 0;
		p = son[p][u];
	}
	return cnt[p];
}
int main()
{
	int n;
	scanf("%d", &n);
	while (n--)
	{
		char op[2];
		scanf("%s%s", op, str);
		if (op[0] == 'I')insert(str);
		else printf("%d\n", query(str));
	}
      	
	return 0;
	
}

在这里插入图片描述

24 合并集

在这里插入图片描述
在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>

const int N = 100010;
int n, m;
int p[N];
int find(int x)//返回x的祖宗节点+路径压缩
{
	if (p[x] != x)p[x] = find(p[x]);
	return p[x];
}
int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) p[i] =  i;
	while (m--)
	{
		char op[2];
		int a, b;
		scanf("%s%d%d", op, &a, &b);
		if (op[0]== 'M')p[find(a)] = p[find(b)];
		else {
			if (find(a) == find(b)) puts("Yes");
			else puts("No");
		}
	}

      	
	return 0;
	
}

在这里插入图片描述

25 连通块中点的数量

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>

const int N = 100010;
int n, m;
int p[N],sized[N];
int find(int x)//返回x的祖宗节点+路径压缩
{
	if (p[x] != x)p[x] = find(p[x]);
	return p[x];
}
int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		p[i] = i;
		sized[i] = 1;
	}
	while (m--)
	{
		char op[5];
		int a, b;
		scanf("%s", op);
		if (op[0] == 'C') {
			scanf("%d%d", &a, &b);
			if (find(a) == find(b))continue;
			sized[find(b)] += sized[find(a)];
			p[find(a)] = find(b);
		}
		else if(op[1]=='1')
		{
			scanf("%d%d", &a, &b);
			if (find(a) == find(b)) puts("Yes");
			else puts("No");
		}
		else
		{
			scanf("%d", &a);
			printf("%d\n", sized[find(a)]);
		}
	}

      	
	return 0;
	
}

在这里插入图片描述

26 推排序

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>

const int N = 100010;
int n, m;
int h[N], sizee;

void down(int u)
{
	int t = u;
	if (2 * u <= sizee && h[2 * u] < h[t])t = 2 * u;
	if (2 * u + 1 <= sizee && h[2 * u + 1] < h[t])t = 2 * u + 1;
	if (u != t)
	{
		swap(h[u], h[t]);
		down(t);
	}
}
int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)scanf("%d", &h[i]);
	sizee = n;
	for (int i = n / 2; i; i--)down(i);
	while(m--)
	{
		printf("%d ", h[1]);
		h[1] = h[sizee];
		sizee--;
		down(1);
	}

      	
	return 0;
	
}

在这里插入图片描述

27 模拟堆

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>

const int N = 100010;
int n, m;
int h[N],ph[N],hp[N], sizee;
void heap_swap(int a, int b)
{
	swap(ph[hp[a]], ph[hp[b]]);
	swap(hp[a], hp[b]);
	swap(h[a], h[b]);
}
void down(int u)
{
	int t = u;
	if (2 * u <= sizee && h[2 * u] < h[t])t = 2 * u;
	if (2 * u + 1 <= sizee && h[2 * u + 1] < h[t])t = 2 * u + 1;
	if (u != t)
	{
		heap_swap(u, t);
		down(t);
	}
}
void up(int u)
{
	while (u / 2 && h[u / 2] > h[u])
	{
		heap_swap(u / 2, u);
		u /= 2;
	}
}
int main()
{
	int n, m = 0;
	scanf("%d", &n);
	while (n--)
	{
		char op[10];
		int k, x;
		scanf("%s", op);
		if (!strcmp(op, "I")) {
			scanf("%d", &x);
			sizee++;
			m++;
			ph[m] = sizee, hp[sizee] = m;
			h[sizee] = x;
			up(sizee);
		}
		else if (!strcmp(op, "PM"))printf("%d\n", h[1]);
		else if (!strcmp(op, "DM"))
		{
			heap_swap(1, sizee);
			sizee--;
			down(1);
		}
		else if (!strcmp(op, "D"))
		{
			scanf(" %d", &k);
			k = ph[k];
			heap_swap(k, sizee);
			sizee--;
			down(k), up(k);
		}
		else
		{
			scanf("%d%d", &k, &x);
			k = ph[k];
			h[k] = x;
			down(k), up(k);
		}
	}
      	
	return 0;
	
}

在这里插入图片描述

28 模拟散列表

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
const int N = 100003;
int h[N], e[N], ne[N],idx;
//拉链法
void insert(int x)
{
	int k = (x % N + N) % N;
	e[idx] = x;
	ne[idx] = h[k];
	h[k] = idx++;
	
}
bool find(int x)
{
	int k = (x % N + N) % N;
	for (int i = h[k]; i != -1; i = ne[i])
		if (e[i] == x)
			return true;
	return false;
	
}

int main()
{
	int n;
	scanf("%d", &n);
	memset(h, -1, sizeof h);
	while (n--)
	{
		char op[2];
		int x;
		scanf("%s%d", op, &x);
		if (*op == 'I')insert(x);
		else
		{
			if (find(x))puts("Yes");
			else puts("No");
		}
	}
	return 0;
	
}

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
const int N = 200003,null=0x3f3f3f3f;//开2~3倍
int h[N];
//开放寻址法
int find(int x)
{
	int k = (x % N + N) % N;
	while (h[k] != null && h[k] != x)
	{
		k++;
		if (k == N)k = 0;
	}
	return k;
}
int main()
{
	int n;
	scanf("%d", &n);
	memset(h, 0x3f, sizeof h);//按字节来memset,int有四个字节
	while (n--)
	{
		char op[2];
		int x;
		scanf("%s%d", op, &x);
		int k = find(x);
		if (*op == 'I')h[k] = x;
		else {
			if (h[k] != null)puts("Yes");
			else puts("No");
		}
	}
	return 0;
	
}

29 字符串哈希

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
const int N = 100010, P = 131;//经验
int n, m;
char str[N];
typedef unsigned long long ULL;//2^64
ULL p[N], h[N];

ULL get(int l, int r)
{
	return h[r] - h[l - 1] * p[r - l + 1];
}

int main()
{
	scanf("%d%d%s", &n, &m, str + 1);
	p[0] = 1;
	for (int i = 1; i <= n; i++)
	{
		p[i] = p[i - 1] * P;
		h[i] = h[i - 1] * P + str[i];

	}
	while (m--)
	{
		int l1, r1, l2, r2;
		scanf("%d%d%d%d", &l1, &r1, &l2, &r2);
		if (get(l1, r1) == get(l2, r2))puts("Yes");
		else puts("No");
	}
	return 0;
	
}

在这里插入图片描述

30 排列数字

在这里插入图片描述

#include<vector>
#include<algorithm>
const int N = 1000001;
int n;
int path[N];
bool st[N];
//DFS
void dfs(int u)
{
	if (u == n)
	{
		for (int i = 0; i < n; i++)printf("%d", path[i]);
		puts("");
		return;
	}
	for (int i = 1; i <= n; i++)
	{
		if (!st[i])
		{
			path[u] = i;
			st[i] = true;
			dfs(u + 1);
			st[i] = false;
		}
	}
}

int main()
{
	cin >> n;
	dfs(0);
	
	
	return 0;
	
}

在这里插入图片描述

31 n-皇后问题

在这里插入图片描述
在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
const int N = 20;
int n;
char g[N][N];
bool col[N], dg[N], udg[N];
//DFS
void dfs(int u)
{
	if (u == n)
	{
		for (int i = 0; i < n; i++)puts(g[i]);
		puts("");
		return;
	}
	for(int i=0;i<n;i++)
		if (!col[i] && !dg[u + i] && !udg[n - u + i])
		{
			g[u][i] = 'Q';
			col[i] = dg[u + i] = udg[n - u + i] = true;
			dfs(u + 1);
			col[i] = dg[u + i] = udg[n - u + i] = false;
			g[u][i] = '.';//剪枝
		}
}

int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			g[i][j] = '.';
	
	dfs(0);
	
	
	return 0;
	
}

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
//枚举
const int N = 20;
int n;
char g[N][N];
bool row[N],col[N], dg[N], udg[N];

void dfs(int x, int y, int s)
{
	if (y == n)y = 0, x++;
	if (x == n)
	{
		if (s == n)
		{
			for (int i = 0; i < n; i++)puts(g[i]);
			puts("");
		}
		return;
	}
	//不放皇后
	dfs(x, y + 1, s);
	//放皇后
	if (!row[x] && !col[y] && !dg[x + y] && !udg[x - y + n])
	{
		g[x][y] = 'Q';
		row[x] = col[y] = dg[x + y] = udg[x - y + n] = true;
		dfs(x, y + 1, s + 1);
		row[x] = col[y] = dg[x + y] = udg[x - y + n] = false;
		g[x][y] = '.';
	}

}
int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			g[i][j] = '.';
	
	dfs(0,0,0);
	
	
	return 0;
	
}

32 走迷宫

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
typedef pair<int, int>PII;
const int N = 110;
int n, m;
int g[N][N];//地图
int d[N][N];//距离,初始-1为没到过
PII q[N * N];//地图中坐标点

int bfs()
{
	int hh = 0, tt = 0;
	q[0] = { 0,0 };
	memset(d, -1, sizeof d);
	d[0][0] = 0;
	int dx[4] = { -1,0,1,0 }, dy[4] = { 0,1,0,-1 };
	while (hh <=tt)
	{
		auto t = q[hh++];
		for (int i = 0; i < 4; i++)
		{
			int x = t.first + dx[i], y = t.second + dy[i];
			if (x >= 0 && x < n && y >= 0 && y < m && g[x][y] == 0 && d[x][y] == -1)
			{
				d[x][y] = d[t.first][t.second] + 1;
				q[++tt] = { x,y };
			}
		}
	}
	return d[n - 1][m - 1];
}

int main()
{
	cin >> n >> m;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			cin >> g[i][j];
	cout << bfs() << endl;
	
	return 0;
	
}

在这里插入图片描述

33 树与图的存储

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
//邻接表
const int N = 100010, M = N * 2;
int h[N], e[M], ne[M], idx;//idx是边

void add(int a, int b)//a指向b
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int main()
{
	memset(h, -1, sizeof h);
	
	return 0;
	
}

34 树的重心

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
const int N = 100010, M = N * 2;

int n, m;
int h[N], e[M], ne[M], idx;
bool st[N];

int ans = N;
void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

//以u为根的子树中点的数量
int dfs(int u) //深度优先遍历
{
	st[u] = true;//标记一下,已经被搜过了

	int sum = 1, res = 0;//sum表示子树大小,res表示删除节点后每一个连通中点数最大值
	for (int i = h[u]; i != -1; i = ne[i])
	{
		int j = e[i];
		if (!st[j])
		{
			int s=dfs(j);
			res = max(res, s);
			sum += s;
		}
	}
	res = max(res, n - sum);
	ans = min(ans, res);

	return sum;
}
int main()
{
	cin >> n;
	memset(h, -1, sizeof h);
	for (int i = 0; i < n - 1; i++)
	{
		int a, b;
		cin >> a >> b;
		add(a, b), add(b, a);
		
	};
	dfs(1);
	cout << ans << endl;
	return 0;
	
}

在这里插入图片描述

35 搜索与图论

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
const int N= 100010;
int n, m;
int h[N], e[N], ne[N], idx;
int d[N], q[N];

void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int bfs()
{
	int hh = 0, tt = 0;
	q[0] = 1;
	memset(d, -1, sizeof d);
	d[1] = 0;
	while (hh <= tt)
	{
		int t = q[hh++];
		for (int i = h[t]; i != -1; i = ne[i])
		{
			int j = e[i];
			if (d[j] == -1)
			{
				d[j] = d[t] + 1;
				q[++tt] = j;
			}
		}
	}

	return d[n];
}
int main()
{
	cin >> n >> m;
	memset(h, -1, sizeof h);
	for (int i = 0; i < m; i++)
	{
		int a, b;
		cin >> a >> b;
		add(a, b);
	}
	cout << bfs() << endl;
	return 0;
	
}

在这里插入图片描述

36 有向图的拓扑排序

在这里插入图片描述

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
//有向无环图也成称为拓扑图
const int N = 100010;
int n,m;
int h[N], e[N], ne[N], idx;
int q[N], d[N];//q[N]表示拓扑排序(入度都为0),d[N]表示各个点的入度。

void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
bool topsort()
{
	int hh = 0, tt = -1;
	for (int i = 1; i <= n; i++)
	{
		if (!d[i])
			q[++tt] = i;
	}
	while (hh <= tt)
	{
		int t = q[hh++];
		for (int i = h[t]; i != -1; i = ne[i])
		{
			int j = e[i];
			d[j]--;
			if (d[j] == 0)q[++tt] = j;
		}
	}
	return tt == n - 1;//当q进去n个
}
int main()
{
	cin >> n >> m;
	memset(h, -1, sizeof h);
	for (int i = 0; i < m; i++)
	{
		int a, b;
		cin >> a >> b;
		add(a, b);
		d[b]++;
		
	}
	if (topsort())
	{
		for (int i = 0; i < n; i++)printf("%d ", q[i]);
		puts("");
	}
	else puts("-1");
	return 0;
	
}

在这里插入图片描述

37 Dijkstra求最短路

在这里插入图片描述## 37.1 朴素Dijkstra算法
在这里插入图片描述
在这里插入图片描述

#pragma warning(disable:4996)
#include<cstring>
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
const int N = 510;
int n, m;
int g[N][N];//邻接矩阵    稠密图(m~ n^2)用邻接矩阵,稀疏图用邻接表
int dist[N];
bool st[N];
int dijkstra()
{
	memset(dist, 0x3f, sizeof dist);
	dist[1] = 0;
	for (int i = 0; i < n; i++)
	{
		int t = -1;
		for (int j = 1; j <= n; j++)
			if (!st[j] && (t == -1 || dist[t] > dist[j]))
				t = j;
		st[t] = true;
		for (int j = 1; j <= n; j++)
			dist[j] = min(dist[j], dist[t] + g[t][j]);
	}
	if (dist[n] == 0x3f3f3f3f)return -1;
	return dist[n];
}
int main()
{
	scanf("%d%d", &n, &m);
	memset(g, 0x3f, sizeof g);
	while (m--)
	{
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		g[a][b] = min(g[a][b], c);
	}
	int t = dijkstra();
	printf("%d\n", t);
	return 0;
	
}

在这里插入图片描述

37.2 堆优化版的Dijkstra算法

在这里插入图片描述

#pragma warning(disable:4996)
#include<cstring>
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<queue>
const int N = 100010;
typedef pair<int, int> PII;
int n, m;
int h[N], e[N], ne[N], idx, w[N];
int dist[N];
bool st[N];
void add(int a, int b, int c)
{
	e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;

}
int dijkstra()
{
	memset(dist, 0x3f, sizeof dist);
	dist[1] = 0;
	priority_queue<PII, vector<PII>, greater<PII>>heap;
	heap.push({ 0,1 });
	while (heap.size())
	{
		auto t = heap.top();
		heap.pop();
		int ver = t.second, distance = t.first;
		if (st[ver])continue;
		str[ver] = true;
		for (int i = h[ver]; i != -1; i = ne[i])
		{
			int j = e[i];
			if (dist[j] > distance + w[i])
			{
				dist[j] = distance + w[i];
				heap.push({ dist[j],j });
			}
		}
	}
	if (dist[n] == 0x3f3f3f3f)return -1;
	return dist[n];
}
int main()
{
	scanf("%d%d", &n, &m);
	memset(h, -1, sizeof h);
	while (m--)
	{
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		add(a,b,c);
	}
	int t = dijkstra();
	printf("%d\n", t);
	return 0;
	
}

在这里插入图片描述

38 有边数限制的最短路

在这里插入图片描述
在这里插入图片描述

#pragma warning(disable:4996)
#include<cstring>
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>

const int N = 510, M = 10010;
int n, m, k;
int dist[N], backup[N];
struct Edge
{
	int a, b, w;
}edges[M];
int bellman_ford()
{
	memset(dist, 0x3f, sizeof dist);
	dist[1] = 0;
	for (int i = 0; i < k; i++)
	{
		memcpy(backup, dist, sizeof dist);
		for (int j = 0; j < m; j++)
		{
			int a = edges[j].a, b = edges[j].b, w = edges[j].w;
			dist[b] = min(dist[b], backup[a] + w);
		}
	}
	if (dist[n] > 0x3f3f3f3f / 2)return -1;//边权存在负数,正无穷加负权更新正无穷
	return dist[n];
}
int main()
{
	scanf("%d%d%d", &n, &m, &k);
	for(int i=0;i<m;i++)
	{
		int a, b, w;
		scanf("%d%d%d", &a, &b, &w);
		edges[i] = { a,b,w };
	}
	int t = bellman_ford();
	if (t == -1)puts("impossible");
	else printf("%d\n", t);
	return 0;
	
}

在这里插入图片描述

39 spfa求最短路

在这里插入图片描述

#pragma warning(disable:4996)
#include<cstring>
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<queue>
const int N = 100010;
typedef pair<int, int> PII;
int n, m;
int h[N], e[N], ne[N], idx, w[N];
int dist[N];
bool st[N];
void add(int a, int b, int c)
{
	e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;

}
int spfa()
{
	memset(dist, 0x3f, sizeof dist);
	dist[1] = 0;
	queue<int>q;
	q.push(1);
	st[1] = true;
	while (q.size())
	{
		int t = q.front();
		q.pop();
		st[t] = false;
		for (int i = h[t]; i != -1; i = ne[i])
		{
			int j = e[i];
			if (dist[j] > dist[t] + w[i])
			{
				dist[j] = dist[t] + w[i];
				if (!st[j])
				{
					q.push(j);
					st[j] = true;
				}
			}
		}
	}
	if (dist[n] == 0x3f3f3f3f)return -1;
	return dist[n];
}
int main()
{
	scanf("%d%d", &n, &m);
	memset(h, -1, sizeof h);
	while (m--)
	{
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		add(a, b, c);
	}
	int t = spfa();
	if (t == -1)puts("impossible");
	else printf("%d\n", t);
	return 0;

}

在这里插入图片描述

40 spfa判断负环

在这里插入图片描述

#pragma warning(disable:4996)
#include<cstring>
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<queue>
const int N = 100010;
typedef pair<int, int> PII;
int n, m;
int h[N], e[N], ne[N], idx, w[N];
int dist[N],cnt[N];
bool st[N];
void add(int a, int b, int c)
{
	e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;

}
int spfa()
{
	queue<int>q;
	for (int i = 1; i <=n; i++)
	{
		st[i] = true;
		q.push(i);
	}
	while (q.size())
	{
		int t = q.front();
		q.pop();
		st[t] = false;
		for (int i = h[t]; i != -1; i = ne[i])
		{
			int j = e[i];
			if (dist[j] > dist[t] + w[i])
			{
				dist[j] = dist[t] + w[i];
				cnt[j] = cnt[t] + 1;
				if (cnt[j] >= n)return true;
				if (!st[j])
				{
					q.push(j);
					st[j] = true;
				}
			}
		}
	}
	return false;
}
int main()
{
	scanf("%d%d", &n, &m);
	memset(h, -1, sizeof h);
	while (m--)
	{
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		add(a, b, c);
	}
	if (spfa())puts("yes");
	else puts("No");
	return 0;

}

在这里插入图片描述

41 Floyd求最短路

在这里插入图片描述

#pragma warning(disable:4996)
#include<cstring>
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>

using namespace std;
const int N = 210, INF = 1e9;
int n, m, Q;
int d[N][N];
void floyd()
{
	for (int k = 1; k <= n; k++)
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
int main()
{
	scanf("%d%d%d", &n, &m, &Q);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			if (i == j)d[i][j] = 0;
			else d[i][j] = INF;
	while (m--)
	{
		int a,b,w;
		scanf("%d%d%d", &a, &b, &w);
		d[a][b] = min(d[a][b], w);
	}
	floyd();
	while (Q--)
	{
		int a, b;
		scanf("%d%d", &a, &b);
		if (d[a][b] > INF / 2)puts("impossible");
		else printf("%d\n", d[a][b]);
	}
	return 0;
}

在这里插入图片描述

42 Prim算法求最小生成树

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#pragma warning(disable:4996)
#include<cstring>
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 510,INF=1e9;
int g[N][N];
int n, m;
int dist[N];
bool st[N];
int prim()
{
	memset(dist, 0x3f, sizeof dist);
	int res = 0;
	for (int i = 0; i <n; i++)
	{
		int t = -1;
		for (int j = 1; j <= n; j++)
			if (!st[j] && (t == -1 || dist[t] > dist[j]))
				t = j;
		if (i && dist[t] == INF)return INF;
		if (i)res += dist[t];
		for (int j = 1; j <= n; j++)dist[j] = min(dist[j], g[t][j]);
		st[t] = true;
	}
	return res;

}
int main()
{
	scanf("%d%d", &n, &m);
	memset(g, 0x3f, sizeof g);
	while (m--)
	{
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		g[a][b] = g[b][a] = min(g[a][b], c);
	}
	int t = prim();
	if (t == INF)puts("impossible");
	else printf("%d\n", t);
	return 0;
}

在这里插入图片描述

43 Kruskal算法求最小生成树

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#pragma warning(disable:4996)
#include<cstring>
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 200010;
int n, m;
int p[N];
struct Edge
{
	int a, b, w;
	bool operator<(const Edge& W)const
	{
		return w < W.w;
	}
}edges[N];
int find(int x)
{
	if (p[x] != x)p[x] = find(p[x]);
	return p[x];
}
int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++)
	{
		int a, b, w;
		scanf("%d%d%d", &a, &b, &w);
		edges[i] = { a,b,w };
	}
	sort(edges, edges + m);
	for (int i = 1; i <= n; i++)p[i] = i;
	int res = 0, cnt = 0;
	for (int i = 0; i <m; i++)
	{
		int a = edges[i].a, b = edges[i].b, w = edges[i].w;
		a = find(a), b = find(b);
		if (a != b)
		{
			p[a] = b;
			res += w;
			cnt++;
		}
	}
	if (cnt < n - 1)puts("impossible");
	else printf("%d\n", res);
	return 0;
}

44 染色体判定二分图

在这里插入图片描述
在这里插入图片描述

#pragma warning(disable:4996)
#include<cstring>
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 100010,M=200010;
int n, m;
int h[N],e[M],ne[M],idx;
int color[N];
void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
bool dfs(int u, int c)
{
	color[u] = c;
	for (int i = h[u]; i != -1; i = ne[i])
	{
		int j = e[i];
		if (!color[j])
		{
			if (!dfs(j, 3 - c))return false;
		}
		else if (color[j] == c)return false;
	}
	return true;
}
int main()
{
	scanf("%d%d", &n, &m);
	memset(h, -1, sizeof h);
	while (m--)
	{
		int a, b;
		scanf("%d%d", &a, &b);
		add(a, b), add(b, a);
	}
	bool flag = true;
	for(int i=1;i<=n;i++)
		if (!color[i])
		{
			if (!dfs(i,1))
			{
				flag = false;
				break;
			}
		}
	if (flag)puts("Yes");
	else puts("No");
	return 0;
}

在这里插入图片描述

45 二分图的最大匹配

在这里插入图片描述

#include<cstring>
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
//匈牙利算法(找对象)
const int N = 510, M = 100010;
int n1, n2, m;
int h[N], e[M], ne[M], idx;
int match[N];//右边匹配
bool st[N];//每次不要重复搜一个点
void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
bool find(int x)
{
	for (int i = h[x]; i != -1; i = ne[i])
	{
		int j = e[i];
		if (!st[j])
		{
			st[j] = true;
			if (match[j] == 0 || find(match[j]))
			{
				match[j] = x;
				return true;
			}
		}
	}
	return false;
}
int main()
{
	scanf("%d%d%d", &n1, &n2, &m);
	memset(h, -1, sizeof h);
	while (m--)
	{
		int a, b;
		scanf("%d%d", &a, &b);
		add(a, b);
	}
	int res = 0;
	for (int i = 1; i <= n1; i++)
	{
		memset(st, false, sizeof st);
		if (find(i))res++;
	}
	printf("%d\n", res);
	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值