个人整理 ACM 模板.docx
《个人整理 ACM 模板.docx》由会员分享,可在线阅读,更多相关《个人整理 ACM 模板.docx(44页珍藏版)》请在冰豆网上搜索。
![个人整理 ACM 模板.docx](https://file1.bdocx.com/fileroot1/2023-1/8/5c700f47-432e-4599-846e-c68df33746c8/5c700f47-432e-4599-846e-c68df33746c81.gif)
个人整理ACM模板
1.头文件
#define_CRT_SBCURE_NO_DEPRECATE
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
usingnamespacestd;
constintmaxn=110;
2.constintINF=0x3f3f3f3f;
经典
1.埃拉托斯特尼筛法
/*
|埃式筛法|
|快速筛选素数|
|16/11/05ztx|
*/
intprime[maxn];
boolis_prime[maxn];
intsieve(intn){
intp=0;
for(inti=0;i<=n;++i)
is_prime[i]=true;
is_prime[0]=is_prime[1]=false;
for(inti=2;i<=n;++i){//注意数组大小是n
if(is_prime[i]){
prime[p++]=i;
for(intj=i+i;j<=n;j+=i)//轻剪枝,j必定是i的倍数
is_prime[j]=false;
}
}
returnp;//返回素数个数
}
2.快速幂
/*
|快速幂|
|16/11/05ztx|
*/
typedeflonglongLL;//视数据大小的情况而定
LLpowerMod(LLx,LLn,LLm)
{
LLres=1;
while(n>0){
if(n&1)//判断是否为奇数,若是则true
res=(res*x)%m;
x=(x*x)%m;
n>>=1;//相当于n/=2;
}
returnres;
}
3.大数模拟
大数加法
/*
|大数模拟加法|
|用string模拟|
|16/11/05ztx,thankstocaojiji|
*/
stringadd1(strings1,strings2)
{
if(s1==""&&s2=="")return"0";
if(s1=="")returns2;
if(s2=="")returns1;
stringmaxx=s1,minn=s2;
if(s1.length()maxx=s2;
minn=s1;
}
inta=maxx.length()-1,b=minn.length()-1;
for(inti=b;i>=0;--i){
maxx[a--]+=minn[i]-'0';//a一直在减,额外还要减个'0'
}
for(inti=maxx.length()-1;i>0;--i){
if(maxx[i]>'9'){
maxx[i]-=10;//注意这个是减10
maxx[i-1]++;
}
}
if(maxx[0]>'9'){
maxx[0]-=10;
maxx='1'+maxx;
}
returnmaxx;
}
大数阶乘
/*
|大数模拟阶乘|
|用数组模拟|
|16/12/02ztx|
*/
#include
#include
usingnamespacestd;
typedeflonglongLL;
constintmaxn=100010;
intnum[maxn],len;
/*
在mult函数中,形参部分:
len每次调用函数都会发生改变,n表示每次要乘以的数,最终返回的是结果的长度
tip:
阶乘都是先求之前的(n-1)!
来求n!
初始化Init函数很重要,不要落下
*/
voidInit(){
len=1;
num[0]=1;
}
intmult(intnum[],intlen,intn){
LLtmp=0;
for(LLi=0;itmp=tmp+num[i]*n;//从最低位开始,等号左边的tmp表示当前位,右边的tmp表示进位(之前进的位)
num[i]=tmp%10;//保存在对应的数组位置,即去掉进位后的一位数
tmp=tmp/10;//取整用于再次循环,与n和下一个位置的乘积相加
}
while(tmp){//之后的进位处理
num[len++]=tmp%10;
tmp=tmp/10;
}
returnlen;
}
intmain(){
Init();
intn;
n=1977;//求的阶乘数
for(inti=2;i<=n;++i){
len=mult(num,len,i);
}
for(inti=len-1;i>=0;--i)
printf("%d",num[i]);//从最高位依次输出,数据比较多采用printf输出
printf("\n");
return0;
}
4.GCD
/*
|辗转相除法|
|欧几里得算法|
|求最大公约数|
|16/11/05ztx|
*/
intgcd(intbig,intsmall)
{
if(small>big)swap(big,small);
inttemp;
while(small!
=0){//辗转相除法
if(small>big)swap(big,small);
temp=big%small;
big=small;
small=temp;
}
return(big);
}
5.LCM
/*
|辗转相除法|
|欧几里得算法|
|求最小公倍数|
|16/11/05ztx|
*/
intgcd(intbig,intsmall)
{
if(small>big)swap(big,small);
inttemp;
while(small!
=0){//辗转相除法
if(small>big)swap(big,small);
temp=big%small;
big=small;
small=temp;
}
return(big);
}
6.全排列
/*
|求1到n的全排列,有条件|
|16/11/05ztx,thankstowangqiqi|
*/
voidPern(intlist[],intk,intn){//k表示前k个数不动仅移动后面n-k位数
if(k==n-1){
for(inti=0;iprintf("%d",list[i]);
}
printf("\n");
}else{
for(inti=k;iswap(list[k],list[i]);
Pern(list,k+1,n);
swap(list[k],list[i]);
}
}
}
7.二分搜索
/*
|二分搜索|
|要求:
先排序|
|16/11/05ztx,thankstowangxiaocai|
*/
//left为最开始元素,right是末尾元素的下一个数,x是要找的数
intbsearch(int*A,intleft,intright,intx){
intm;
while(leftm=left+(right-left)/2;
if(A[m]>=x)right=m;elseleft=m+1;
//如果要替换为upper_bound,改为:
if(A[m]<=v)x=m+1;elsey=m;
}
returnleft;
}
/*
最后left==right
如果没有找到135577找6,返回7
如果找有多少的x,可以用lower_bound查找一遍,upper_bound查找一遍,下标相减
C++自带的lower_bound(a,a+n,x)返回数组中最后一个x的下一个数的地址
upper_bound(a,a+n,x)返回数组中第一个x的地址
如果a+n内没有找到x或x的下一个地址,返回a+n的地址
lower_bound(a,a+n,x)-upper_bound(a,a+n,x)返回数组中x的个数
*/
数据结构
并查集
8.并查集
/*
|合并节点操作|
|16/11/05ztx,thankstochaixiaojun|
*/
intfather[maxn];//储存i的father父节点
voidmakeSet(){
for(inti=0;ifather[i]=i;
}
intfindRoot(intx){//迭代找根节点
introot=x;//根节点
while(root!
=father[root]){//寻找根节点
root=father[root];
}
while(x!
=root){
inttmp=father[x];
father[x]=root;//根节点赋值
x=tmp;
}
returnroot;
}
voidUnion(intx,inty){//将x所在的集合和y所在的集合整合起来形成一个集合。
inta,b;
a=findRoot(x);
b=findRoot(y);
father[a]=b;//y连在x的根节点上或father[b]=a为x连在y的根节点上;
}
/*
在findRoot(x)中:
路径压缩迭代最优版
关键在于在路径上的每个节点都可以直接连接到根上
*/
图论
MST
最小生成树
Kruskal
9.克鲁斯卡尔算法
/*
|Kruskal算法|
|适用于稀疏图求最小生成树|
|16/11/05ztxthankstowangqiqi|
*/
/*
第一步:
点、边、加入vector,把所有边按从小到大排序
第二步:
并查集部分+下面的code
*/
voidKruskal(){
ans=0;
for(inti=0;iif(Find(edge[i].a)!
=Find(edge[i].b)){
Union(edge[i].a,edge[i].b);
ans+=edge[i].len;
}
}
}
Prim
10.普里姆算法
/*
|Prim算法|
|适用于稠密图求最小生成树|
|堆优化版,时间复杂度:
O(elgn)|
|16/11/05ztx,thankstochaixiaojun|
*/
structnode{
intv,len;
node(intv=0,intlen=0):
v(v),len(len){}
booloperator<(constnode&a)const{//加入队列的元素自动按距离从小到大排序
returnlen>a.len;
}
};
vectorG[maxn];
intvis[maxn];
intdis[maxn];
voidinit(){
for(inti=0;iG[i].clear();
dis[i]=INF;
vis[i]=false;
}
}
intPrim(ints){
priority_queueQ;//定义优先队列
intans=0;
Q.push(node(s,0));//起点加入队列
while(!
Q.empty()){
nodenow=Q.top();Q.pop();//取出距离最小的点
intv=now.v;
if(vis[v])continue;//同一个节点,可能会推入2次或2次以上队列,这样第一个被标记后,剩下的需要直接跳过。
vis[v]=true;//标记一下
ans+=now.len;
for(inti=0;iintv2=G[v][i].v;
intlen=G[v][i].len;
if(!
vis[v2]&&dis[v2]>len){
dis[v2]=len;
Q.push(node(v2,dis[v2]));//更新的点加入队列并排序
}
}
}
returnans;
}
Bellman-Ford
单源最短路
Dijkstra
11.迪杰斯特拉算法
/*
|Dijkstra算法|
|适用于边权为正的有向图或者无向图|
|求从单个源点出发,到所有节点的最短路|
|优化版:
时间复杂度O(elbn)|
|16/11/05ztx,thankstochaixiaojun|
*/
structnode{
intv,len;
node(intv=0,intlen=0):
v(v),len(len){}
booloperator<(constnode&a)const{//距离从小到大排序
returnlen>a.len;
}
};
vectorG[maxn];
boolvis[maxn];
intdis[maxn];
voidinit(){
for(inti=0;iG[i].clear();
vis[i]=false;
dis[i]=INF;
}
}
intdijkstra(ints,inte){
priority_queueQ;
Q.push(node(s,0));//加入队列并排序
dis[s]=0;
while(!
Q.empty()){
nodenow=Q.top();//取出当前最小的
Q.pop();
intv=now.v;
if(vis[v])continue;//如果标记过了,直接continue
vis[v]=true;
for(inti=0;iintv2=G[v][i].v;
intlen=G[v][i].len;
if(!
vis[v2]&&dis[v2]>dis[v]+len){
dis[v2]=dis[v]+len;
Q.push(node(v2,dis[v2]));
}
}
}
returndis[e];
}
SPFA
12.最短路径快速算法(ShortestPathFasterAlgorithm)
/*
|SPFA算法|
|队列优化|
|可处理负环|
*/
vectorG[maxn];
boolinqueue[maxn];
intdist[maxn];
voidInit()
{
for(inti=0;iG[i].clear();
dist[i]=INF;
}
}
intSPFA(ints,inte)
{
intv1,v2,weight;
queueQ;
memset(inqueue,false,sizeof(inqueue));//标记是否在队列中
memset(cnt,0,sizeof(cnt));//加入队列的次数
dist[s]=0;
Q.push(s);//起点加入队列
inqueue[s]=true;//标记
while(!
Q.empty()){
v1=Q.front();
Q.pop();
inqueue[v1]=false;//取消标记
for(inti=0;iv2=G[v1][i].vex;
weight=G[v1][i].weight;
if(dist[v2]>dist[v1]+weight){//松弛操作
dist[v2]=dist[v1]+weight;
if(inqueue[v2]==false){//再次加入队列
inqueue[v2]=true;
//cnt[v2]++;//判负环
//if(cnt[v2]>n)return-1;
Q.push(v2);
}}}
}
returndist[e];
}
/*
不断的将s的邻接点加入队列,取出不断的进行松弛操作,直到队列为空
如果一个结点被加入队列超过n-1次,那么显然图中有负环
*/
Floyd-Warshall
13.弗洛伊德算法
/*
|Floyd算法|
|任意点对最短路算法|
|求图中任意两点的最短距离的算法|
*/
for(inti=0;ifor(intj=0;jscanf("%lf",&dis[i][j]);
}
for(intk=0;kfor(inti=0;ifor(intj=0;jdis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
二分图
14.染色法
/*
|交叉染色法判断二分图|
|16/11/05ztx|
*/
intbipartite(ints){
intu,v;
queueQ;
color[s]=1;
Q.push(s);
while(!
Q.empty()){
u=Q.front();
Q.pop();
for(inti=0;iv=G[u][i];
if(color[v]==0){
color[v]=-color[u];
Q.push(v);
}
elseif(color[v]==color[u])
return0;
}
}
return1;
}
15..匈牙利算法
/*
|求解最大匹配问题|
|递归实现|
|16/11/05ztx|
*/
vectorG[maxn];
boolinpath[maxn];//标记
intmatch[maxn];//记录匹配对象
voidinit()
{
memset(match,-1,sizeof(match));
for(inti=0;iG[i].clear();
}
}
boolfindpath(intk){
for(inti=0;iintv=G[k][i];
if(!
inpath[v]){
inpath[v]=true;
if(match[v]==-1||findpath(match[v])){//递归
match[v]=k;//即匹配对象是“k妹子”的
returntrue;
}
}
}
returnfalse;
}
voidhungary(){
intcnt=0;
for(inti=1;i<=m;i++){//m为需要匹配的“妹子”数
memset(inpath,false,sizeof(inpath));//每次都要初始化
if(findpath(i))cnt++;
}
cout<}
/*
|求解最大匹配问题|
|dfs实现|
|16/11/05ztx|
*/
intv1,v2;
boolMap[501][501];
boolvisit[501];
intlink[501];
intresult;
booldfs(intx){
for(inty=1;y<=v2;++y){
if(Map[x][y]&&!
visit[y]){
visit[y]=true;
if(link[y]==0||dfs(link[y])){
link[y]=x;
returntrue;
}}}
return