ACM 模板

常用函数&&数据

strrve() 将字符前后颠倒
strtol() 将字符串转换成长整型数
strtoul() 将字符串转换成无符号长整型数
strtod() 将字符串转换成浮点数
strchr() 查找某字符在字符串中首次出现的位置
strlwr() 将字符串字符全部变成小写
strupr()将字符串字符全部变成大写
二分图
1.最大匹配=最大流
2.最小覆盖集=最小割=V-最大匹配数
3.最大独立集=总点数-最小覆盖集=顶点数-最大搭配数
4.最大点权独立集=总权值-最小点权覆盖集
5.最小点权覆盖集=最小割
6.最小点覆盖= V-最大匹配数
7.最小不相交路径覆盖=V-最大匹配数

string b=a.substr(a,b) 把string a的第a到b个字符赋给b;

next_permutation(); prev_permutation();
floor()向下取整; ceil(); 向上取整;

构造 n的5次方的矩阵系数
1 5 10 10 5 1
1 4 6 4 1
1 3 3 1
1 2 1
1 1
1
在 S 中任选 r 个元素的排列称为S的r排列,当r = n时,有公式 P(n; n1 * a1, n2 * a2, …, nk * ak) = n! / (n1! * n2! * … * nk!)
在 S 中任选 r 个元素的组合称为S的r组合,当r<=任意ni时,有公式 C(n; n1 * a1, n2 * a2, …, nk * ak) = C(k+r-1, r),
由公式可以看出多重集合的组合只与类别数k 和选取的元素r 有关,与总数无关!

#pragma GCC optimize(2) O2优化
#pragma GCC optimize(3,"Ofast","inline") O3优化

一.图论

1.最短路径

1.1dijkstra

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define maxn 100
#define sf scanf
#define pf printf
using namespace std;
int n,m,x,y,z;  //n个城市和m条道路
int mp[maxn][maxn],lowcost[maxn],vis[maxn],pre[maxn];
void dijkstra(int sta,int edd){
   
    for(int i=0;i<n;i++) lowcost[i]=mp[sta][i];
    vis[sta]=1; lowcost[sta]=0;
    //寻找距离原点最小的点加进集合 (除原点) 
    for(int i=1;i<n;i++){
   
        int Min=inf;
        int v=-1;
        for(int j=0;j<n;j++){
   
            if(!vis[j]&&lowcost[j]<Min){
   
                Min=lowcost[j];
                v=j;
            }
        }

        //如果又一次更新失败退出此次循环 
        if(Min==inf) {
   
            break;
        }
        vis[v]=1;
        //用新加进来的点松弛
        for(int k=0;k<n;k++){
   
            if(!vis[k]&&lowcost[v]+mp[v][k]<lowcost[k]){
   
                lowcost[k]=lowcost[v]+mp[v][k];
                pre[k]=v;
            }
        } 
    }
}

int main(){
   
    sf("%d%d",&n,&m);
    for(int i=0;i<n;i++){
   
        for(int j=0;j<n;j++){
   
            mp[i][j]=inf;
        }
        mp[i][i]=0;
    }
    for(int i=0;i<m;i++){
   
        sf("%d%d%d",&x,&y,&z);
        mp[x][y]=mp[y][x]=z;
    }
    dijkstra(0,n-1);

    if(lowcost[n-1]==inf ) cout<<"-1"<<endl;
    else cout<<lowcost[n-1]<<endl;  

    //假设打印起点是0,终点是n-1的路径
    int sta=0,ed=n-1;
    pre[sta]=-1;
    vector<int> ve;
    vector<int>::iterator ite;
    while(pre[ed]!=-1){
   
        ve.push_back(ed);
        ed=pre[ed];
    } 
    reverse(ve.begin(),ve.end());
    cout<<sta<<" ";
    for(ite=ve.begin();ite!=ve.end();++ite){
   
        cout<<*ite;
        if(ite!=ve.end()) cout<<" ";
        else cout<<endl;
    }
    return 0;
}

1.2.floyed

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define maxn 100
#define sf scanf
#define pf printf
using namespace std;
int n,m,x,y,z;  //n个城市和m条道路
int mp[maxn][maxn],lowcost[maxn],vis[maxn],pre[maxn],flag=false;

//k是中间结点,i是起点,j是终点 
void floyed(int mp[][maxn]){
   
    for(int k=0;k<n;k++){
   
        for(int i=0;i<n;i++){
   
            for(int j=0;j<n;j++){
   
                if(mp[i][j]>mp[i][k]+mp[k][j]){
   
                    mp[i][j]=mp[i][k]+mp[k][j];
                }
            }
        }
    }
}
int main(){
   
    sf("%d%d",&n,&m);
    for(int i=0;i<n;i++){
   
        for(int j=0;j<n;j++){
   
            mp[i][j]=inf;
        }
        mp[i][i]=0;
    }
    for(int i=0;i<m;i++){
   
        sf("%d%d%d",&x,&y,&z);
        mp[x][y]=mp[y][x]=z;
    }
    floyed(mp);
    //可以判断是否存在负环
    for(int i=0;i<n;i++){
   
        if(mp[i][i]<0){
   
            flag=true;
        }
    } 
    if(flag) cout<<"存在负环"<<endl;
    else cout<<"不存在负环"<<endl; 
//  cout<<mp[0][n-1]<<endl; 
    return 0;
}

1. 3.优先队列优化(记录路径)

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>

using namespace std;
#define pa pair<int,int>
int n,m;
const long long inf=0x3f3f3f3f3f3f3f3f;

int fa[10000];//记录路径
long long d[10000];
//int flag[10000];
struct pr{
   
	int to,cost;
};
struct pe{
   
	int x,y;
	bool friend operator< (pe s,pe t)
	{
   
		if(s.x !=t.x) return s.x>t.x;
		else return s.y>t.y;
	}
};
vector<pr>ve[10000];
void bfs()
{
   
	priority_queue<pe>q;
	fill(d+1,d+n+1,inf);
//	memset(flag,0,sizeof flag);
	d[1]=0;
	//flag[1]=1;
	pe c;
	c.x =0,c.y=1;
	q.push(c);
	while(!q.empty() ) 
	{
   
		c=q.top() ;
		q.pop() ;
		int v=c.y;
		if(v==n)
		{
   
			break;
		}
		if(d[v]<c.x ) continue;
		for(int i=0;i<ve[v].size();i++)
		{
   
			pr e=ve[v][i];
			if((d[e.to]>d[v]+e.cost))
			{
   	
				d[e.to]=d[v]+e.cost ;
				fa[e.to]=v ;
			//	flag[e.to]=1;
				c.x =d[e.to];c.y =e.to;
				q.push(c); 
			}
		}
	}
}

int main()
{
   
	int x,y,s;
	scanf("%d%d",&n,&m);
	for(int i=0;i<m;i++)
	{
   
		scanf("%d%d%d",&x,&y,&s);
		pr c;
		c.cost =s;c.to =y;
		ve[x].push_back(c);
	}
	bfs();
	printf("%lld\n",d[n]);
	printf("%d",n);
	while(fa[n]!=1)
	{
   
		printf(" %d",fa[n]);
		n=fa[n];
	}
	printf(" 1\n");
	return 0;
}

2.拓扑排序

#include<vector>
#include<queue>
#include<iostream>
#include<cstring>
using namespace std;
int in[10100];// 存入度 
vector<int>v[10100];// 存关系 构建图 
int main()
{
   
    int m,n;
    int x,y;
    while(cin>>n>>m)// 根据题目要求可以改动 
    {
   
        memset(in,0,sizeof(in));// 清空入度 
        for(int i=1;i<=n;i++) v[i].clear() ;// 清空vector 
        while(m--)// m组数据 
        {
   
            cin>>y>>x;
            in[y]++;// y的关系大于x,x指向y y的入度+1; 
            v[x].push_back(y);// 就 y 放在 x后面 
        }
        queue<int>q;// 定义一个队列 最为节点的删除 
        for(int i=1;i<=n;i++)
        {
   
            if(!in[i]) {
           // 入度为零的节点放入 队列   
                q.push(i);
            }    
        }
        while(!q.empty() )
        {
   
            int xx=q.front() ; //  如果队列中一次存了大于 2 个节点 
            q.pop() ;         //说明该图有 2->3 && 2->4 这种情况 有点个点之间没有关系
            n--;             // 总节点数 -1; 
            for(int i=0;i<v[xx].size() ;i++)  // 遍历这个节点后面的 点 
            {
   
                int yy=v[xx][i];
                in[yy]--;                    //  删除 x 后 yy 的入度就 -1;  
                if(!in[yy]) {
          //  如果此时 yy 入度为零放入队列 遍历他的下一个节点 
                   q.push(yy);   
                } 
            }
        }
        if(n) cout<<"该图有环"<<endl;  // 如果总结点数没减为零 说明有环的存在    
    }
    return 0;
}

3.LCA

3.1倍增LCA

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>

using namespace std;
#define pa pair<int,int>
const int mn=1e5;
int fa[mn][60];//记录2的j次方个节点是谁 
int depth[mn];//记录深度 
int bit[mn];//作为2进制 
int in[mn];//存入度方便找根节点 
int dis[mn];
vector<pa>ve[mn];//存图; 

void dfs(int x,int y,int s)
{
   
	depth[x]=depth[y]+1;//x是y的儿子 所以深度加一 
	dis[x]=dis[y]+s;
	fa[x][0]=y;
	for(int i=1;i<=29;i++) fa[x][i]=fa[fa[x][i-1]][i-1];//这个节点的的第2的j次方等于2的j-1次方的那个值得2的j-1次方; 
	for(int i=0;i<ve[x].size() ;i++)                  // 建议画个图理解一下 
	{
   
		//pa xx=ve[x][i];
		int X=ve[x][i].first;
		int Y=ve[x][i].second;
		if(x==X) continue;//这里用的双向存图所以一旦xx=其父节点 
		//depth[xx]=depth[y]+1;就可以不管了 
		dfs(X,x,Y);//继续搜索 
	}
}
int lca(int x,int y)
{
   
	if(depth[y]>depth[x])//让x比y深 
	{
   
		swap(x,y);
	}
	int dif=depth[x]-depth[y];//取差值方便以后进行调深度 
	for(int i=29;i>=0;i--)
	{
   
		if(dif>=bit[i])//调到同一深度 
		{
   
			x=fa[x][i];
			dif-=bit[i];
		}
	}
	//这个也是调到同一深度 
	if(x==y) return x;//如果现在节点已经相同那么就输出就行了 
	for(int i=29;i>=0;i--)
	{
   //从大到小慢慢遍历合适的节点; 
		if(depth[x]>=bit[i]&&fa[x][i]!=fa[y][i])
		{
   
			x=fa[x][i];
			y=fa[y][i];
		}
	}
	return fa[x][0];
}
int main()
{
   
	int n,m,t,x,y,d;
	bit[0]=1;
	for(int i=1;i<=29;i++)
	{
   
		bit[i]=bit[i-1]<<1;
	}
	while(~scanf("%d",&t))
	{
   
		while(t--)
		{
   
			scanf("%d%d",&n,&m);
			for(int i=1;i<=n;i++)
			{
   
				depth[i]=0;
				dis[i]=0;
				in[i]=0;
				ve[i].clear() ;
			}
			memset(fa,0,sizeof fa);
			//	printf("%dssssssss\n",bit[8]);
			for(int i=1;i<n;i++)
			{
   
				scanf("%d%d%d",&x,&y,&d);
				ve[x].push_back(make_pair(y,d));//因为不确定谁是定点就双向存图; 
				in[y]++;
			}
			int s;
			for(int i=1;i<=n;i++)
			{
   
				if(in[i]==0) {
   
					s=i;
					break;
				}
			}
			dfs(s,0,0);
			while(m--)
			{
   
				scanf("%d%d",&x,&y);
				int ss=lca(x,y);
				printf("%d\n",dis[x]+dis[y]-2*dis[ss]);
			}
		}
	}
	return 0;
}

3.2 tarjan

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>

using namespace std;
#define in =read()
#define ll long long 
const int size = 500000 + 50;
ll n,m,s;
ll site1,site2;
ll head[size],father[size],vis[size],qhead[size],num[size];

struct apoint{
   
    ll x; ll y;
}a[2*size];
struct qpoint{
   
    ll x; ll y; ll z;
}q[2*size];

inline ll read()
{
   
    ll num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
   
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
   
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

ll find(ll x)
{
   
    if(father[x]!=x)father[x]=find(father[x]);
    return father[x];
}

inline void unionn(ll x,ll y)
{
   
    ll xx=find(x),yy=find(y);
    father[yy]=xx;
}

inline void add(ll x,ll y)
{
   
    a[++site1].x=head[x];
    a[site1].y=y;
    head[x]=site1;
}

inline void qadd(ll x,ll y,ll z)
{
   
    q[++site2].x=qhead[x];
    q[site2].y=y;
    q[site2].z=z;
    qhead[x]=site2;
}

inline void tarjan(ll x)
{
   
    vis[x]=1;
    int y,z;
    for(int i=head[x];i;i=a[i].x){
   
        y=a[i].y;
        if(!vis[y]){
   
            tarjan(y); unionn(x,y);
        }
    }
    for(int i=qhead[x];i;i=q[i].x){
   
        y=q[i].y; z=q[i].z;
        if(vis[y])num[z]=find(y);
    }
}

int main()
{
   
    n in; m in; s in;
    int x,y;
    for(int i=1;i<n;i++){
   
        x in; y in;
        add(x,y); add(y,x);
    }
    for(int i=1;i<=n;i++)father[i]=i;
    for(int i=1;i<=m;i++){
   
        x in; y in;
        qadd(x,y,i); qadd(y,x,i);
    }
    tarjan(s);
    for(int i=1;i<=m;i++){
   
        printf("%d\n",num[i]);
    }
}

4.树的直径

//**************************dfs*********************
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int n,tot,a,b,ans,pos;
int first[200010],nxt[200010];
struct edge
{
   
    int u,v;
}l[200010];
void build(int f,int t)
{
   
    l[++tot]=(edge){
   f,t};
    nxt[tot]=first[f];
    first[f]=tot;
}
void dfs(int k,int fa,int d)
{
   
    if(d>ans)
    {
   
        ans=d;
        pos=k;
    }
    for(int i=first[k];i!=-1;i=nxt[i])
    {
   
        int x=l[i].v;
        if(x==fa)
        continue;
        dfs(x,k,d+1);
    }
}
int main()
{
   
    memset(first,-1,sizeof(first));
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
   
        scanf("%d%d",&a,&b);
        if(a!=0)
        {
   
            build(i,a);
            build(a,i);
        }
        if(b!=0)
        {
   
            build(i,b);
            build(b,i);
        }
    }
    dfs(1,1,0);//第一遍DFS找出树上深度最深的点
    ans=0;
    dfs(pos,1,0);//第二遍DFS由深度最深的点向上找最长链
    printf("%d",ans);
    return 0;   
}
/bfs************************************
//记录各个节点到其最远的距离
#include<iostream>
#include<algorithm> 
#include<iostream>
#include<cstring>
#include<vector>

using namespace std;

typedef pair<int,int> pa;
int n,maxlen,s;
vector<pa>v[100100];
int dp[100100];

int dfs(int x,int y,int l)
{
   
	if(maxlen<=l)
	{
   
		maxlen=l;
		s=x;
	}
	pa p;
	for(int i=0;i<v[x].size() ;i++)
	{
   
		p=v[x][i];
		if(p.first ==y) continue;
		else
		{
   	
			dfs(p.first ,x,l+p.second);
			dp[p.first]=max(dp[p.first],l+p.second);
		}
	}
}

int main()
{
   
	while(cin>>n)
	{
   
		int x,y;
		memset(dp,0,sizeof dp);
		for(int i=0;i<=n;i++) v[i].clear() ;
		for(int  i=2;i<=n;i++)
		{
   
			cin>>x>>y;
			v[x].push_back(make_pair(i,y));
			v[i].push_back(make_pair(x,y));  
		}
		s=0;
		maxlen=0;
		maxlen=0;
		dfs(1,-1,0);
		dfs(s,-1,0);
		dfs(s,-1,0);
		for(int i=1;i<=n;i++) cout<<dp[i]<<endl;
	}
	return 0;
} 

5.并查集(带权)

#include<string.h>
#include<stdio.h>
#include<algorithm>

using namespace std;

int fa[30500];// 存节点 
int a[30500];// 以该节点为父节点的节点一共有几个 
int b[30200];//  该节点到其父节点的距离 

int find(int x)
{
   // 整个程序的核心算法 递归用的真是666666 
	if(fa[x]!=x)
	{
   
		int s=fa[x];// 将其上一个节点的值付给s 
		fa[x]=find(fa[x]);
		a[x]+=a[s];//x到其祖先节点的值等于他到他父节点的值加
				  //上起父节点到其祖先节点的距离 
	}
	return fa[x];
}

void jion(int x,int y)
{
   
	int xx=find(x);
	int yy=find(y);
	if(xx!=yy)
	{
   
		fa[yy]=xx;
		a[yy]+=b[xx];//因为把yy的父节点接到xx的父节点后面了 
		b[xx]+=b[yy];//所以yy到最终祖先节点的距离等于他到本来的祖先的距离 
	}  //加上xx到其祖先节点的距离,此时新的祖先节点的子孙 
}	//数量等于 以前 xx 的子孙加上 yy 的祖孙; 

int main()
{
   
	int n,x,y;
	char c;
	while(~scanf("%d",&n))
	{
   
		for(int i=1;i<=30009;i++)
		{
   
			a[i]=0;//自己到自己的距离为0;
			b[i]=1;//刚开始的时候每个节点都是一个祖先节点包含自己所以为1;
			fa[i]=i;//第i个值为自己方便以后找祖先节点
		}
		while(n--)
		{
   
			scanf(" %c",&c);
			if(c=='M')
			{
   
				scanf("%d%d",&x,&y);
				jion(x,y);
			}
			else {
   
				scanf("%d",&x);
				int s=find(x);//查找 x的祖先节点 
				printf("%d\n",b[s]-a[x]-1);
			}//  x 下面的节点等于总结点数减去x到祖先节点的个数 
		}
	}
	return 0;
}

6.ST表

#include<bits/stdc++.h>
using namespace std;
int n,m,f[100005][21],l,r;
int main()
{
   
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&f[i][0]);
	for(int j=1;j<=21;j++)
		for
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 图论 3 1.1 术语 3 1.2 独立集、覆盖集、支配集之间关系 3 1.3 DFS 4 1.3.1 割顶 6 1.3.2 桥 7 1.3.3 强连通分量 7 1.4 最小点基 7 1.5 拓扑排序 7 1.6 欧拉路 8 1.7 哈密顿路(正确?) 9 1.8 Bellman-ford 9 1.9 差分约束系统(用bellman-ford解) 10 1.10 dag最短路径 10 1.11 二分图匹配 11 1.11.1 匈牙利算法 11 1.11.2 KM算法 12 1.12 网络流 15 1.12.1 最大流 15 1.12.2 上下界的网络的最大流 17 1.12.3 上下界的网络的最小流 17 1.12.4 最小费用最大流 18 1.12.5 上下界的网络的最小费用最小流 21 2 数论 21 2.1 最大公约数gcd 21 2.2 最小公倍数lcm 22 2.3 快速幂取模B^LmodP(O(logb)) 22 2.4 Fermat小定理 22 2.5 Rabin-Miller伪素数测试 22 2.6 Pollard-rho 22 2.7 扩展欧几里德算法extended-gcd 24 2.8 欧拉定理 24 2.9 线性同余方程ax≡b(mod n) 24 2.10 中国剩余定理 25 2.11 Discrete Logging(BL == N (mod P)) 26 2.12 N!最后一个不为0的数字 27 2.13 2^14以内的素数 27 3 数据结构 31 3.1 堆(最小堆) 31 3.1.1 删除最小值元素: 31 3.1.2 插入元素和向上调整: 32 3.1.3 堆的建立 32 3.2 并查集 32 3.3 树状数组 33 3.3.1 LOWBIT 33 3.3.2 修改a[p] 33 3.3.3 前缀和A[1]+…+A[p] 34 3.3.4 一个二维树状数组的程序 34 3.4 线段树 35 3.5 字符串 38 3.5.1 字符串哈希 38 3.5.2 KMP算法 40 4 计算几何 41 4.1 直线交点 41 4.2 判断线段相交 41 4.3 三点外接圆圆心 42 4.4 判断点在多边形内 43 4.5 两圆交面积 43 4.6 最小包围圆 44 4.7 经纬度坐标 46 4.8 凸包 46 5 Problem 48 5.1 RMQ-LCA 48 5.1.1 Range Minimum Query(RMQ) 49 5.1.2 Lowest Common Ancestor (LCA) 53 5.1.3 Reduction from LCA to RMQ 56 5.1.4 From RMQ to LCA 57 5.1.5 An<O(N), O(1)> algorithm for the restricted RMQ 60 5.1.6 An AC programme 61 5.2 最长公共子序列LCS 64 5.3 最长上升子序列/最长不下降子序列(LIS) 65 5.3.1 O(n^2) 65 5.3.2 O(nlogn) 66 5.4 Joseph问题 67 5.5 0/1背包问题 68 6 组合数学相关 69 6.1 The Number of the Same BST 69 6.2 排列生成 71 6.3 逆序 72 6.3.1 归并排序求逆序 72 7 数值分析 72 7.1 二分法 72 7.2 迭代法(x=f(x)) 73 7.3 牛顿迭代 74 7.4 数值积分 74 7.5 高斯消元 75 8 其它 77
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值