板子汇总

1.树状数组板子
https://blog.csdn.net/henulmh/article/details/98596306
2.0x3f3f3f3f与0x7fffffff
https://blog.csdn.net/JuJuBang/article/details/105603867
MAXINT 0x7fffffff
MININT 0x80000000
3.最短路
堆优化dij的链式前向星实现

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<string.h>
using namespace std;
const int N = 1e5 + 3;
struct edge { int w, to, next; };
struct node {
	int dis, num;
	bool operator< (const node &x) const {
		return dis>x.dis;
	}
};
priority_queue<node> que;
int dis[N];
int head[N];
edge E[2*N];
int vis[N];
int cnt;
int n, m, s;
void addedge(int u,int v,int w) {
	cnt++;
	E[cnt].to = v;
	E[cnt].w = w;
	E[cnt].next = head[u];
	head[u] = cnt;
}

void dij() {
	dis[s] = 0;
	que.push(node{ 0,s });
	while (que.empty() == false) {
		node temp;
		temp = que.top();
        que.pop();
		int num = temp.num;
		if (vis[num]) continue;
		else vis[num] = 1;
		for (int i = head[num]; i; i = E[i].next) {
			int tot = E[i].to;
			if (dis[tot] > dis[num] + E[i].w){
				dis[tot] = dis[num] + E[i].w;
				if (!vis[tot]) que.push(node{ dis[tot],tot });
			}
		}
	}
}
int main() {
	cin >> n >> m >> s;
	memset(dis, 0x3f, sizeof(dis));
	for (int i = 1; i <= m; i++) {
		int u, v, w;
		cin >> u >> v >> w;
		addedge(u, v, w);
	}
	dij();
	for (int i = 1; i <= n; i++) {
		cout << dis[i] << " ";
	}
	return 0;
}

bf算法

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<string.h>
using namespace std;
const int N = 1e4 + 5;
const int M = 5e5 + 5;
int n, m, s;
int u[N];
int v[N];
int w[N];
int dis[N];
int main() {
	cin >> n >> m >> s;
	memset(dis, 0x3f, sizeof(dis));
	for (int i = 1; i <= m; i++) {
		cin >> u[i] >> v[i] >> w[i];
	}
	dis[s] = 0;
	int flag = 1;
	for (int i = 1; i <= n - 1; i++) {
		flag = 1;
		for (int j = 1; j <= m; j++) {
			
			if (dis[u[j]] + w[j] < dis[v[j]]) {
				dis[v[j]] = dis[u[j]] + w[j];
				flag = 0;
			}

		}
		if (flag == 1) break;//松弛完毕提前退出
	}
	for (int i = 1; i <= n; i++) {
		cout << dis[i] << " ";
	}

}

SPFA算法

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<string.h>
using namespace std;
const int N = 1e4 + 5;
const int M = 5e5 + 5;
int n, m, s;
int dis[N];
int	inq[N];
struct edge {
	int to, next, w;
};
int cnt;
edge E[M];
int head[N];

void add_edge(int u, int v, int w) {
	cnt++;
	E[cnt].to = v;
	E[cnt].w = w;
	E[cnt].next = head[u];
	head[u] = cnt;
}
void spfa() {
	memset(dis, 0x3f, sizeof(dis));
	queue<int> que;
	que.push(s);
	dis[s] = 0;
	inq[s] = 1;
	while (que.empty() == false) {
		int t = que.front();
		que.pop();
		inq[t] = 0;
		for (int j = head[t]; j; j = E[j].next) {
			int tot = E[j].to;
			if (dis[tot] > dis[t] + E[j].w) {
				dis[tot] = dis[t] + E[j].w;
				if (!inq[tot]) {//注意这里只有进行松弛的边才有机会加入queue
					que.push(tot);
					inq[tot] = 1;
				}
			}
		}
	}

}

int main() {
	cin >> n >> m >> s;
	
	for (int i = 1; i <= m; i++) {
		int u, v, w;
		cin >> u >> v >> w;
		add_edge(u, v, w);
	}
	
	spfa();
	for (int i = 1; i <= n; i++) {
		if (dis[i] == 0x3f3f3f3f) cout << 0x7fffffff << " ";
		else cout << dis[i] << " ";
	}

}

4.判断负环
贝尔曼·福特

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<string.h>
using namespace std;

struct Edge {
	int u = 0, v = 0, w = 0;
};

Edge E[6005];

int dis[2005];

int add(int a, int b) {∞+x=∞,所以要手写加法函数判断这种情况
	if (a == 0x3f3f3f3f || b == 0x3f3f3f3f)
		return 0x3f3f3f3f;
	else
		return a + b;
}

int main() {
	int t;
	cin >> t;
	while (t--) {
		memset(E, 0, sizeof(E));
		memset(dis, 0x3f, sizeof(dis));
		int n, m;
		cin >> n >> m;

		dis[1] = 0;
		int cnt = 1;
		for (int i = 1; i <= m; i++) {
			cin >> E[cnt].u >> E[cnt].v >> E[cnt].w;
			if (E[cnt].w >= 0) {
				E[cnt + 1].v = E[cnt].u;
				E[cnt + 1].u = E[cnt].v;
				E[cnt + 1].w = E[cnt].w;
				cnt++;
			} 
			cnt++;
		}


		for (int i = 1; i < n; i++) {
			int flag = true;
			for (int j = 1; j < cnt; j++) {
				if (add(dis[E[j].u], E[j].w) < dis[E[j].v]) {
					dis[E[j].v] = dis[E[j].u] + E[j].w, flag = false;
				}

			}
			if (flag == true) break;
		}
		int f1 = 0;
		for (int j = 1; j < cnt; j++) {
			if (add(dis[E[j].u], E[j].w) < dis[E[j].v]) {
				cout << "YES" << endl; f1 = 1; break;
			}

		}
		if (f1 == 0) cout << "NO" << endl;
	}

}

spfa

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<string>
#include<queue>
using namespace std;
const int M = 6e3 + 5;
const int N = 2e3 + 5;
int cnt = 0;
int dis[N];
int inq[N];
int coun[N];
int head[N];
int n, m;
struct E { int to, next, w; };
E edge[M];

void add_edge(int u, int v, int w) {
	cnt++;
	edge[cnt].to = v;
	edge[cnt].w = w;
	edge[cnt].next = head[u];
	head[u] = cnt;
}

int add(int a, int b) {
	if (a == 0x3f3f3f3f || b == 0x3f3f3f3f)
		return 0x3f3f3f3f;
	else return a + b;
}
void init() {
	cnt = 0;
	memset(dis, 0x3f, sizeof(dis));
	memset(inq, 0, sizeof(inq));
	memset(coun, 0, sizeof(coun));
	memset(head, 0, sizeof(head));
}
bool spfa() {
	queue<int> que;
	que.push(1);
	inq[1] = 1;
	dis[1] = 0;
	while (!que.empty()) {
		int t = que.front();
		que.pop();
		inq[t] = 0;
		for (int j = head[t]; j; j = edge[j].next) {
			int tot = edge[j].to;
			if (dis[tot] >add( dis[t] , edge[j].w)) {
				dis[tot] = add(dis[t], edge[j].w);
				coun[tot]++;
				if (coun[tot] >= n) return true;//存在负环
				if (!inq[tot]) {
					inq[tot] = 1;
					que.push(tot);
				}
			}
		}
	}
	return false;

}
int main() {
	int t;
	cin >> t;
	while (t--) {
		cin >> n >> m;
		init();
		for (int i = 1; i <= m; i++) {
			int u, v, w;
			cin >> u >> v >> w;
			add_edge(u, v, w);
			if (w > 0) add_edge(v, u, w);
		}
		if (spfa()) cout << "YES" << endl;
		else cout << "NO" << endl;
	}

}

5.最小生成树
递归并查集+kruskal

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int M = 2e5 + 4;
const int N = 5e3 + 4;

struct edge {
	int u, v, w;
};
edge E[M];
int f[N];
bool cmp(edge a, edge b) {
	return a.w < b.w;
}
int father(int u) {//返回u的祖宗
	if (u == f[u]) return u;
	else {
		f[u] = father(f[u]);//路径压缩,没有找到祖宗就继续找父亲的祖宗
		return f[u];
	}
}


int main() {
	int ans = 0;
	int cnt = 0;
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		cin >> E[i].u >> E[i].v >> E[i].w;
	}
	
	for (int i = 1; i <= n; i++) {
		f[i] = i;
	}
	sort(E + 1, E + 1 + m, cmp);

	for (int i = 1; i <= m; i++) {
		int u = father(E[i].u);
		int v = father(E[i].v);
		if (u==v) continue;
		else {
			f[u] = v;//注意这里是求父亲以后再进行赋值的!!!
			cnt++;//加入一条边
			ans += E[i].w;
		} 
		if (cnt == n - 1) {//加入n-1条边,n个顶点最少要n-1条边才能连接在一起
			cout << ans << endl;
			return 0;
		}
	}
	if (cnt < n - 1) {
		cout << "orz" << endl;
		return 0;
	}
}

prim+链式前向星

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<string>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
int n, m;
const int N = 5e3 + 4;
const int M = 2e5+4 ;
struct edge { int to, next, w; };
int cnt;
int head[N];
edge e[2*M];
void add_edge(int u, int v, int w) {
	cnt++;
	e[cnt].w = w;
	e[cnt].next = head[u];
	e[cnt].to = v;
	head[u] = cnt;
}
int dis[N];
int vis[N];
int prim() {
	int ans = 0;
	//prim算法是合并顶点,所以任选一个为起点即可
	memset(dis, 0x3f, sizeof(dis));
	dis[1] = 0;
	vis[1] = 1;
	int num = 1;//生成树中的顶点数目
	for (int i = head[1]; i; i = e[i].next) {
		int tot = e[i].to;
		dis[tot] = min(dis[tot],e[i].w) ;//特别注意,合并边的时候可能会出现重边,所以这里要用min!!!prim是对边进行合并的!
	}
	
	while (num < n) {
		int min = 0x3f3f3f3f;
		int u = -1;
		for (int i = 1; i <= n; i++) {
			if (!vis[i] && dis[i] < min) {
				min = dis[i];//每次选择与生成树距离最小的顶点新加入生成树
				u = i;
			}
		}
		if (u == -1) break;//无法继续加入顶点了
		vis[u] = 1;
		ans += min;
		num++;
		for (int i = head[u]; i; i = e[i].next) {
			int tot = e[i].to;
			if (!vis[tot] && dis[tot] > e[i].w) {
				dis[tot] = e[i].w;//更新各点与最小生成树之间的距离,这里是直接更新为两点之间的边权
			}
		}
	}
	if (num == n ) return ans;
	else return -1;//图不联通
	
}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		int u, v, w;
		cin >> u >> v >> w;
		add_edge(u, v, w);
		add_edge(v, u, w);
	}
	int ans=prim();
	if (ans == -1) {
		cout << "orz" << endl;
	}
	else
		cout << ans << endl;
}

6.并查集求图中存在的最小环

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
const int N=2e5+3;
int fa[N],a[N];
int getf(int x,int &cnt){
    cnt++;
    if(x==fa[x]) return x;
    else{
        return getf(fa[x],cnt);//由于需要求最小环的长度,所以不能进行路径压缩
    }
}
int ans=0x3f3f3f3f;
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        fa[i]=i;
    }
    
    for(int i=1;i<=n;i++){
        cin>>a[i];
        int cnt=0;
        if(getf(a[i],cnt)==i){
            ans=min(ans,cnt);
        }
        else{
            fa[i]=a[i];
        }
    }
    cout<<ans<<endl;
}

**7.线性筛/欧拉筛

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<string>
#include<queue>
using namespace std;
typedef long long ll;
int f[1000005];
int prime[1000005];
int keep[1000005];
int ans = 0;
int shai(int x) {
	int cnt = 0;
	for (int i = 2; i <= x; i++) {
		if (f[i] == 0) {
			prime[cnt++] = i;
		}
		keep[i] = cnt;
		for (int j = 0; j < cnt; j++) {
			if (prime[j] * i > x) break;
			f[i*prime[j]] = 1;
			if (i%prime[j] == 0) break;
		}

	}
}


int main() {
	int n, m;
	cin >> n >> m;
	shai(m);
	while (n--) {
		int l, r;
		cin >> l >> r;
		if (!(l >= 1 && r <= m)) {
			printf("Crossing the line\n");
			continue;
		}
		else {

			printf("%d\n", keep[r] - keep[l - 1]);
		}
	}
}

8.kmp

#include<iostream>
#include<stdio.h>
#include<vector>
#include<string>
#include<queue>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
void prefix_table(int prefix[], string pattern) {//求next数组
	prefix[0] = 0;
	int len = 0;
	int n = pattern.length();
	int i = 1;
	while (i < n) {
		if (pattern[i] == pattern[len]) {
			len++;
			prefix[i] = len;
			i++;
		}
		else {
			if (len > 0) {
				len = prefix[len - 1];
			}
			else {
				prefix[i] = len;
				i++;
			}
		}
	}
}

void move_prefix(int prefix[], int n) {//移动前缀数组
	for (int i = n - 1; i > 0; i--) {
		prefix[i] = prefix[i - 1];
	}
	prefix[0] = -1;
}

void kmp_search( string text, string pattern) {//kmp搜索
	int n = text.length();
	int m = pattern.length();
	int i = 0, j = 0;
	
	int *prefix=(int*)malloc(sizeof(int)*(m));//动态分配数组内存
	int *prefix_keep = (int*)malloc(sizeof(int)*(m));
	prefix_table(prefix, pattern);
	for (int i = 0; i < m; i++) {
		prefix_keep[i] = prefix[i];
	}
	move_prefix(prefix, m);
	while (i < n) {
		if (j == m - 1 && text[i] == pattern[j]) {
			printf("%d\n", i+1-j);
			j = prefix[j];
		}

		if (text[i] == pattern[j]) {
			i++;
			j++;
		}
		else {
			j = prefix[j];
			
			if(j==-1)
			{
				i++; 
				j++;//j==0,从头开始匹配
			}
		}
	}
	for (int i = 0; i < m; i++) {
		cout << prefix_keep[i] << " ";
	}
}

9.刷题集锦
(1)最大正方形 leetcodeP221:二维dp

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        int dp[1000][1000]={0};
        int ans=0;
        for(int i=0;i<matrix.size();i++){
            for(int j=0;j<matrix[0].size();j++){
                if(matrix[i][j]=='1')
                    dp[i][j]=1;
                ans=max(ans,dp[i][j]);
            }
        }
    
    
        for(int i=1;i<matrix.size();i++){
            for(int j=1;j<matrix[0].size();j++){
                if(matrix[i][j]=='1')
                    dp[i][j]=min(dp[i-1][j-1],min(dp[i][j-1],dp[i-1][j]))+1;//(i,j为正方形右下角坐标)
                ans=max(ans,dp[i][j]);
            }
        }
        return ans*ans;
    }
   
};

(2)树状dp+背包思想,通过链式前向星实现
luogu P2014

#include<iostream>
#include<stdio.h>
#include<vector>
#include<string>
#include<queue>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
//树上的选与不选的问题,树状dp
const int N = 300;
struct edge {
	int next, to, w;
};
int m, n;
int cnt;
edge e[N];
int head[N];
void add(int u,int v,int w) {
	cnt++;
	e[cnt].to = v;
	e[cnt].w = w;
	e[cnt].next = head[u];
	head[u] = cnt;
}
int dp[N][N];//在以i为根结点的树中选j个的最大值
void dyp(int x) {//x为根节点时进行dp
	for (int i = head[x]; i; i = e[i].next) {
		int tot = e[i].to;
		dyp(tot);//先对子树进行dp,全部子树结果获得了以后才能得到最终结果
		for (int j = m+1; j >=1 ; j--) { //倒序,压缩空间,省略了对结点数目进行的循环dp[i][j][k],i个节点,前j个选k个
			for (int k = 0; k <= j-1; k++) {
				dp[x][j] = max(dp[x][j], dp[tot][k]+ dp[x][j- k]);//对所有的子树
			}//从dp[x][i-1][j - k]转换过来的,选了父节点才可以选子节点
		}
	}

}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		int k, s;
		cin >> k >> s;
		add(k, i, s);//从k->i,i为儿子
		dp[i][1] = s;
	}
	dyp(0);
	cout << dp[0][m+1] << endl;//注意需要加上0结点,所以一共是m+1个
}

(3)分组dp,主件附件依赖luoguP1064

#include<bits/stdc++.h>
using namespace std;
struct item{
    int v,p,q;
};
item I[61];
int fj[61][61];//主件携带的附件
int cnt[61];//记录附件的个数
int dp[32010];
int h[32010];
int main(){
    int N,m;
    cin>>N>>m;
    for(int i=1;i<=m;i++){
        cin>>I[i].v>>I[i].p>>I[i].q;//i 件物品的价格、重要度以及它对应的的主件
        I[i].p*=I[i].v;
        if(I[i].q){//使每件物品的价格与重要度的乘积的总和最大。
            cnt[I[i].q]++;
            fj[I[i].q][cnt[I[i].q]]=i;
        }
    }
    for(int i=1;i<=m;i++){
        if(I[i].q==0)//分组背包
        {
            for(int j=N;j>=I[i].v;j--)
                h[j]=dp[j-I[i].v]+I[i].p;
            for(int z=1;z<=cnt[i];z++){
                for(int q=N;q>=I[fj[i][z]].v+I[i].v;q--)
                    h[q]=max(h[q],h[q-I[fj[i][z]].v]+I[fj[i][z]].p);
                }
            for(int j=N;j>=I[i].v;j--){
                    dp[j]=max(h[j],dp[j]);
        }
    }}
    cout<<dp[N]<<endl;
}

leetcode 三数之和(双指针法实现)
class Solution {
public:
vector<vector> threeSum(vector& nums){
int n=nums.size();
sort(nums.begin(),nums.end());

    set<vector<int> > se;
    for(int i=0;i<n;i++){
        if(i>0) 
            if(nums[i]==nums[i-1])
                continue;
        int begin=i+1;
        int end=n-1;
        while(begin<end){
            if(nums[begin]+nums[i]+nums[end]==0){
                se.insert({nums[begin],nums[i],nums[end]});
                begin++;
                end--;
            }
            else if(nums[begin]+nums[i]+nums[end]>0){
                end--;
            }
            else if(nums[begin]+nums[i]+nums[end]<0){
                begin++;
            }
        }
    }
    vector<vector<int> > answ(se.begin(),se.end());//使用set进行vector的初始化
    return answ;

}

};
leetcode 1367. 二叉树中的列表//巧妙的dfs,两次递归过程

class Solution {
public:
    bool dfs(ListNode* head, TreeNode* root) {
        if(head==NULL )return true;
        if(root==NULL) return false;
        if(head->val!=root->val){
            return false;
        }
        return dfs(head->next,root->left)||dfs(head->next,root->right);
    }
    bool isSubPath(ListNode* head, TreeNode* root) {
        if(head!=NULL&&root==NULL) return false;
        return dfs(head,root)||isSubPath(head,root->left)||isSubPath(head,root->right);
    }
    

};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值