Acwing 蓝桥备战第五天(常用算法模板)

注意
本文章只对蓝桥杯可能用到的算法模板,借助算法基础课的内容进行简单整理,不涉及算法原理及推导证明。

快速排序

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int a[N];
int n;
void quick_sort(int a[],int l,int r){
    if(l>=r) return; //递归出口
    int i=l-1,j=r+1;
    int x=a[(l+r)/2];
    while(i<j){
        do i++; while(a[i]<x);
        do j--; while(a[j]>x);
        if(i<j) swap(a[i],a[j]);
    }
    quick_sort(a,l,j);
    quick_sort(a,j+1,r);
}
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    quick_sort(a,0,n-1);
    for(int i=0;i<n;i++) printf("%d ",a[i]);
    return 0;
}

归并排序

#include<iostream>
using namespace std;
const int N=100010;
int a[N],tmp[N];
int n;
void merge_sort(int a[],int l,int r){
    if(l>=r) return;
    int mid=(l+r)/2;
    merge_sort(a,l,mid),merge_sort(a,mid+1,r);
    int i=l,j=mid+1,k=0;
    while(i<=mid&&j<=r){
        if(a[i]<a[j]) tmp[k++]=a[i++];
        else tmp[k++]=a[j++];
    }
    while(i<=mid) tmp[k++]=a[i++];
    while(j<=r) tmp[k++]=a[j++];
    for(int i=l,j=0;i<=r;i++,j++) a[i]=tmp[j];
}
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    merge_sort(a,0,n-1);
    for(int i=0;i<n;i++) printf("%d ",a[i]);
    return 0;
}

整数二分(数的范围)

#include<iostream>
using namespace std;
const int N=100010;
int a[N];
int n,q,k;
int main(){
    scanf("%d%d",&n,&q);
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    while(q--){
        int x;
        scanf("%d",&x);
        int l=0,r=n-1;
        while(l<r){
            int mid=(l+r)/2;
            if(a[mid]>=x) r=mid;
            else l=mid+1;
        }
        if(a[l]!=x) printf("-1 ");
        else printf("%d ",l);
        l=0,r=n-1;
        while(l<r){
            int mid=(l+r+1)/2;
            if(a[mid]<=x) l=mid;
            else r=mid-1;
        }
        if(a[l]!=x) printf("-1\n");
        else printf("%d\n",l);
    }
    return 0;
}

一维前缀和

#include<iostream>
using namespace std;
const int N=100010;
int s[N];
int main(){
    int n,m;
    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;
}

二维前缀和(借助画图分析)

#include<iostream>
using namespace std;
const int N=1010;
int a[N][N];
int s[N][N];
int n,m,q;
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-1][j]+s[i][j-1]-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[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]);
    }
}

一维差分

#include<iostream>
using namespace std;
const int N=100010;
int a[N],b[N];
int n,m;
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]);
        insert(i,i,a[i]);
    }
    
    while(m--){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        insert(a,b,c);
    }
    
    for(int i=1;i<=n;i++) a[i]=a[i-1]+b[i];
    
    for(int i=1;i<=n;i++) printf("%d ",a[i]);
    return 0;
}

差分矩阵(重点复习)

#include<iostream>
using namespace std;
const int N=1010;
int a[N][N],b[N][N];
int n,m,q;
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(){
    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]);
            insert(i,j,i,j,a[i][j]);
        }
    }
    
    while(q--){
        int x1,y1,x2,y2,c;
        scanf("%d%d%d%d%d",&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]);
        }
        printf("\n");
    }
    return 0;
}

单调栈

#include<iostream>
#include<stack>
using namespace std;
stack<int> stk;
int n;
int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        int x;
        cin>>x;
        while(!stk.empty()&&stk.top()>=x) stk.pop();
        if(stk.empty()) printf("-1 ");
        else printf("%d ",stk.top());
        stk.push(x);
    }
    return 0;
}

滑动窗口

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int a[N];
int n,k;
deque<int> q;
int main(){
    scanf("%d%d",&n,&k);
    
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    
    for(int i=1;i<=n;i++){
        while(q.size()&&q.back()>a[i]) q.pop_back();
        q.push_back(a[i]);
        if(i-k>=1&&a[i-k]==q.front()){
            q.pop_front();
        }
        if(i>=k){
            cout<<q.front()<<" ";
        }
    }
    
    q.clear();
    cout<<endl;
    
    for(int i=1;i<=n;i++){
        while(q.size()&&q.back()<a[i]) q.pop_back();
        q.push_back(a[i]);
        if(i-k>=1&&a[i-k]==q.front()){
            q.pop_front();
        }
        if(i>=k){
            cout<<q.front()<<" ";
        }
    }
    return 0;
}

朴素KMP

#include<iostream>
using namespace std;
const int N=1e5+10;
const int M=1e6+10;
char p[N],s[M];
int n,m;
int ne[N];
int main(){
    cin>>n>>(p+1)>>m>>(s+1);
    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;
    }
    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);
        }
    }
    
    return 0;
}

KMP求周期

#include<bits/stdc++.h>
using namespace std;
//s长度为n,s存在最小循环节,最小循环节的长度 n-ne[n],如果存在周期,T=n/(n-ne[n]) 
const int N=1e6+10;
char p[N];
int ne[N];
int main(){
	while(1){
		cin>>(p+1);
		if(p[1]=='.') break;
		int n=strlen(p+1);
		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;
		}
		if(n%(n-ne[n])==0) printf("%d\n",n/(n-ne[n]));
		else printf("1\n");
	}
	return 0;
}

并查集

#include<iostream>
using namespace std;
const int N=1e5+10;
int p[N];
int n,m;
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=1;i<=n;i++) p[i]=i; //初始化,开始之前每个结点指向自己
    
    while(m--){
        string s;
        int a,b;
        cin>>s;
        if(s=="M"){
            cin>>a>>b;
            a=find(a),b=find(b);
            if(a!=b){
                p[a]=b;
                //a的祖先结点不等于b的祖先结点,两者不在一个集合,让a的祖先结点的父节点指向b的祖先
            }
        }else{
            cin>>a>>b;
            a=find(a),b=find(b);
            if(a==b){
                printf("Yes\n");
            }else{
                printf("No\n");
            }
        }
    }
    return 0;
}

BFS

#include<bits/stdc++.h>
using namespace std;
const int N=110;
int g[N][N];
int dis[N][N];
typedef pair<int,int> PII;
#define x first
#define y second
int n,m;
int bfs(PII start,PII end){
    memset(dis,-1,sizeof dis);
    queue<PII> q;
    dis[start.x][start.y]=0;
    q.push(start);
    while(q.size()){
        auto a=q.front();
        q.pop();
        int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
        for(int i=0;i<4;i++){
            int x=a.x+dx[i];
            int y=a.y+dy[i];
            if(x<1||x>n||y<1||y>m) continue; //越界
            if(g[x][y]==1) continue; //障碍
            if(dis[x][y]!=-1) continue; //已经被扩展
            dis[x][y]=dis[a.x][a.y]+1;
            if(x==n&&y==m) return dis[x][y];
            q.push({x,y});
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    
    PII start,end;
    
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&g[i][j]);
        }
    }
    
    start={1,1},end={n,m};
    
    int distance=bfs(start,end);
    
    printf("%d",distance);
    return 0;
}

朴素迪杰斯特拉求单源最短路

#include<bits/stdc++.h>
using namespace std;
const int N=510;
int g[N][N];
int dis[N];
bool st[N];
int n,m;
int dijkstra(){
    memset(dis,0x3f,sizeof dis);
    dis[1]=0;
    for(int i=0;i<n-1;i++){
        int t=-1;
        for(int j=1;j<=n;j++){
            if(!st[j]&&(t==-1||dis[t]>dis[j])){
                t=j;
            }
        }
        for(int j=1;j<=n;j++)
        dis[j]=min(dis[j],dis[t]+g[t][j]);
        st[t]=1;
    }
    if(dis[n]==0x3f3f3f3f) return -1;
    else return dis[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 distance=dijkstra();
    printf("%d",distance);
    return 0;
}

弗洛伊德求多源最短路

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

prim求最小生成树

#include<bits/stdc++.h>
using namespace std;
const int N=510;
const int INF=0x3f3f3f3f;
int g[N][N];
int dis[N];
bool st[N];
int n,m;
int prime(){
    memset(dis,0x3f,sizeof dis);
    int ans=0;
    for(int i=0;i<n;i++){
        int t=-1;
        for(int j=1;j<=n;j++){
            if(!st[j]&&(t==-1||dis[t]>dis[j])){
                t=j;
            }
        }
        if(i&&dis[t]==INF) return INF;
        if(i) ans+=dis[t];
        st[t]=1;
        for(int j=1;j<=n;j++){
            dis[j]=min(dis[j],g[t][j]);
        }
    }
    return ans;
}
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=prime();
    if(t==INF) printf("impossible\n");
    else printf("%d\n",t);
    return 0;
}

Kruskal算法求最小生成树

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int p[3*N];
struct Edge{
    int a,b,w;
}edge[2*N];
int n,m;
bool cmp(Edge c,Edge d){
    return c.w<d.w;
}
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,c;
        scanf("%d%d%d",&a,&b,&c);
        edge[i]={a,b,c};
    }
    
    for(int i=1;i<=n;i++) p[i]=i;
    sort(edge,edge+m,cmp);
    
    int ans=0,cnt=0;
    for(int i=0;i<m;i++){
        int a=edge[i].a,b=edge[i].b,w=edge[i].w;
        a=find(a),b=find(b);
        if(a!=b){
            p[a]=b;
            ans+=w;
            cnt++;
        }
    }
    if(cnt<n-1) printf("impossible\n");
    else printf("%d",ans);
    return 0;
}

声明
所有模板借鉴于yxc算法基础课,仅供自己复习蓝桥使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值