文章目录
常用函数&&数据
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