算法模板大全-超详细~

首先声明!!!


  • 1.内容可能有点多,涵盖大部分的基础算法,后续补充。

  • 2.此为总结归纳,可能会有雷同,如有使用注明出处。

  • 3.如有改进地方欢迎批评指正~@(。・o・)@~


一、基础算法

1.排序:

1.1 冒泡排序:

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int n;
int g[N];

//冒泡排序 
void bubble_sort()
{
    for(int i=0;i<n;i++)
        for(int j=0;j<n-i-1;j++)
            if(g[j]>g[j+1])
                swap(g[j],g[j+1]);
}


int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>g[i];
	
    bubble_sort();
	
    for(int i=0;i<n;i++) cout<<g[i]<<' ';
	
    return 0;
}

1.2 选择排序

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int n;
int g[N];

//选择排序 
void selection_sort()
{
    for(int i=0;i<n-1;i++){
        int min=i;
        
        for(int j=i+1;j<n;j++){ 
            if(g[j]<g[min])
                min=j;
        }
        
        swap(g[min],g[i]);
    }	
}


int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>g[i];
	
    selection_sort();
	
    for(int i=0;i<n;i++) cout<<g[i]<<' ';
	
    return 0;
}

1.3 插入排序

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int n;
int g[N];

//插入排序 
void insertion_sort()
{ 
    for(int i=1;i<n;i++){
        int res=g[i];
        int j=i-1;
		
        while(j>=0&&g[j]>res){
            g[j+1]=g[j];
            j--;
        }
		
        g[j+1]=res;
    }	
}


int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>g[i];
	
    insertion_sort();
	
    for(int i=0;i<n;i++) cout<<g[i]<<' ';
	
    return 0;
}

1.4 快速排序

#include<iostream>
#include<algorithm> 

using namespace std;

const int N=1e5+10;

int q[N];
int n;

//快速排序 
void quick_sort(int q[],int l,int r)
{
    if(l>=r) return;
	
    int x=q[(l+r)>>1],i=l-1,j=r+1;
    while(i<j){
        do i++; while(q[i]<x);
        do j--; while(q[j]>x);
        if(i<j) swap(q[i],q[j]);
    }
	
    quick_sort(q,l,j);
    quick_sort(q,j+1,r);
}


int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%d",&q[i]);
	
    quick_sort(q,0,n-1);
	
    for(int i=0;i<n;i++) printf("%d ",q[i]);
	 
    return 0;
}

1.5 归并排序

#include<iostream>
#include<algorithm> 

using namespace std;

const int N =1e5+10;

int q[N],tmp[N];
int n;

//归并排序
void mergesort(int q[],int l,int r)
{
    if(l>=r) return;

    int mid=l+r>>1;

    mergesort(q,l,mid),mergesort(q,mid+1,r);

    int k=0,i=l,j=mid+1;
    while(i<=mid&&j<=r){
        if(q[i]<=q[j]) tmp[k++]=q[i++];
        else  tmp[k++]=q[j++];
    }
        
    while(i<=mid) tmp[k++]= q[i++];
    while(j<=r) tmp[k++]=q[j++];

    for (i=l,j=0;i<=r;i++,j++) q[i]=tmp[j];
}


int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++ ) scanf("%d",&q[i]);

    mergesort(q,0,n-1);

    for (int i=0;i<n;i++) printf("%d ",q[i]);

    return 0;
}

2.二分

2.1 整数二分

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int q[N];
int n,m;


int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++) scanf("%d",&q[i]);
	
    while(m--){
        int x;
        scanf("%d",&x);
		
        int l=0,r=n-1;
        while(l<r){
            int mid=l+r>>1;
            if(q[mid]>=x) r=mid;
            else l=mid+1;
        }
		
        if(q[l]!=x) printf("-1 -1\n");
        else{
            printf("%d ",l);
            int l=0,r=n-1;
            while(l<r){
                int mid=l+r+1>>1;
                if(q[mid]<=x) l=mid;
                else r=mid-1;
            }
            printf("%d\n",l);
        }
    }
	
    return 0;
}

2.2 小数二分

#include<iostream>
#include<algorithm>

using namespace std;


int main()
{
    double n;
    cin>>n;
    
    double l=-10000,r=10000;
    while(r-l>1e-8){
        double mid=(l+r)/2;
        if(mid*mid*mid>=n) r=mid;
        else  l=mid;
    }
    
    printf("%.6lf",l);
    
    return 0;
}

3.前缀和

3.1 线性前缀和

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int n,m;
int g[N],s[N];


int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>g[i],s[i]=s[i-1]+g[i];
	
    while(m--){
        int l,r;
        cin>>l>>r;
        cout<<s[r]-s[l-1]<<endl;
    }
	
    return 0;
}

3.2 二维前缀和

#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;

const int N=1010;

int n,m,p;
int g[N][N],s[N][N];


int main()
{
    cin>>n>>m>>p;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>g[i][j];
            s[i][j]=s[i][j-1]+s[i-1][j]-s[i-1][j-1]+g[i][j];
        }
    }
	
    while(p--){
        int x1,x2,y1,y2;
        cin>>x1>>y1>>x2>>y2;
        LL sum=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
        cout<<sum<<endl;
    }
	
    return 0;
} 

4.差分

4.1 线性差分

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int a[N],b[N];
int n,m;


int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        b[i]=a[i]-a[i-1];
    }
	
    while(m--){
        int l,r,c;
        scanf("%d%d%d",&l,&r,&c);
        b[l]+=c;
        b[r+1]-=c;
    }
	
    for(int i=1;i<=n;i++){
        a[i]=a[i-1]+b[i];
        printf("%d ",a[i]);
    }
	
    return 0;
} 

4.2 二维差分

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1010;

int n,m,q;
int a[N][N],b[N][N];

//差分函数 
void insert(int x1,int y1,int x2,int y2,int c)
{
    b[x1][y1]+=c;
    b[x2+1][y1]-=c;
    b[x1][y2+1]-=c;
    b[x2+1][y2+1]+=c;
}


int main()
{
    cin>>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;
        cin>>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];
            printf("%d ",b[i][j]);
        }
        printf("\n");
    }
	
    return 0;
}

5.双指针

5.1 头尾指针

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int  a[N],b[N];
int n,m,x;


int main()
{
    cin>>n>>m>>x;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<m;i++) cin>>b[i];
	
    int i,j=m-1;
    for(i=0;i<n;i++){
        while(j>=0&&a[i]+b[j]>x) j--;
        if(a[i]+b[j]==x) break;
    }
	
    cout<<i<<' '<<j<<endl;
	
    return 0;
}

5.2 头双指针

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int n,m;
int a[N],b[N];


int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<m;i++) cin>>b[i];
	
    for(int i=0,j=0;i<m;i++){
        if(a[j]==b[i]) j++;
        if(j==n){
            printf("Yes");
            return 0;
        }
    }
    
    printf("No");
	
    return 0;
}

5.3 快慢指针(链表)

 public class ListNode {
      int val;
      ListNode next;
      ListNode() {}
      ListNode(int val) { this.val = val; }
      ListNode(int val, ListNode next) { this.val = val; this.next = next; }
  }
class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode p = head, q = head;
        while(q != null && q.next != null){
            q = q.next.next;
            p = p.next;
        }
        return p;
    }
}

6.贪心

6.1 区间选点

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

struct Range{
    int l,r;
}range[N];

bool cmp(Range a,Range b)
{
    if(a.r==b.r) return a.l<b.r;
    return a.r<b.r;
}


int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++) cin>>range[i].l>>range[i].r;
	
    sort(range,range+n,cmp);
	
    int sum=1,res=range[0].r;
    for(int i=1;i<n;i++){
        if(res<range[i].l){
            res=range[i].r;
            sum++;
        }
    }
	
    cout<<sum<<endl;
	
    return 0;
}

6.2 区间分组

#include<iostream>
#include<algorithm>
#include<queue>

using namespace std;

priority_queue <int,vector<int>,greater<int> > heap;

const int N=1e5+10;

struct Range{
    int l,r;
}range[N];


bool cmp(Range a,Range b){
    return a.l<b.l;
}


int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++) cin>>range[i].l>>range[i].r;
	
    sort(range,range+n,cmp);
	
    for(int i=0;i<n;i++){
        Range r=range[i];
        if(heap.empty()||heap.top()>=r.l) heap.push(r.r);
        else{
            heap.pop();
            heap.push(r.r);
        }
    }
	
    cout<<heap.size()<<endl;
	
    return 0;
}

6.3 哈夫曼树

#include<iostream>
#include<algorithm>
#include<queue>

using namespace std;

priority_queue<int,vector<int>,greater<int> > q;


int main()
{
    int n,p;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&p);
        q.push(p);
    }
    
    int x,y,sum=0;
    while(q.size()>1){
        x=q.top();
        q.pop();
        y=q.top();
        q.pop();
        q.push(x+y);
        sum+=x+y;
    }
	
    printf("%d",sum);
	
    return 0;
}

6.4 选址问题

#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;

const int N=1e5+10;

int n;
int g[N];


int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>g[i];
	
    sort(g,g+n);
	
    LL sum=0;
    for(int i=0;i<n;i++) sum+=abs(g[i]-g[n/2]);
	
    cout<<sum<<endl;
	
    return 0;
}

6.5 推公式

#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;

const int N=1e5+10;

int n;
LL ct[N];

struct P{
    int x,y,z;
}g[N];


bool cmp(P a,P b){
    return a.z<b.z;
}


int main()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        int a,b;
        cin>>a>>b;
        g[i].x=a,g[i].y=b,g[i].z=a+b;
    }
	
    sort(g+1,g+n+1,cmp);
	
    for(int i=1;i<=n;i++) ct[i]=ct[i-1]+g[i].x;
	
    LL sum=-2e17;
    for(int i=1;i<=n;i++){
        LL t=ct[i-1]-g[i].y;
        sum=max(sum,t);
    }
	
    cout<<sum<<endl;
	
    return 0;
}

7.位运算

7.1 朴素版

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int a[N];


int check(int n)
{
    int sum=0;
    while(n){
        if(n&1) sum++;
        n>>=1;
    }
    return sum;
}


int main()
{
    int n;
    scanf("%d",&n);
	
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        printf("%d ",check(a[i]));
    }
	
    return 0;
}

7.2 x&-x

#include<iostream>
#include<algorithm>

using namespace std;

int main()
{
    int n;
    scanf("%d",&n);
    
    while(n--)
    {
        int x,s=0;
        scanf("%d",&x);
        
        for(int i=x;i;i-=i&-i) s++ ;

        printf("%d ",s);
    }

    return 0;
}

二、数据结构

1.线性表

1.1 数组

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int n;
int g[N];


int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>g[i];
	
    for(int i=0;i<n;i++) cout<<g[i]<<' ';
	
    return 0;
}

1.2 哈希表

#include<iostream>
#include<algorithm>
 
using namespace std;

const int N=1e5+3,null=1e9+7;   

int h[N];
int n;


int find(int x)
{
    int k=(x%N+N)%N;
    while(h[k]!=null&&h[k]!=x){
        if(k==N) k=0;
        k++;
    }
    return k;
}


int main()
{
    scanf("%d",&n);
    fill(h,h+N,null);
	
    while(n--){
        int x;
        char op[2];
        scanf("%s%d",&op,&x);
        int k=find(x); 
		
        if(op[0]=='I') h[k]=x;
        else{
            if(h[k]==null) printf("No\n");
            else  printf("Yes\n");
        }
    }
    return 0;
}

2.链表

说明:C++里有三种链表的应用方法
  • 1.指针(最基本的链表)
  • 2.结构体(链表的一个变种)
  • 3.数组模拟(运行速度快,理解起来有点绕)
这里主要展示数组模拟~

2.1 单链表

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

//head 表示头结点的下标 
//e[i] 表示节点i的值 
//ne[i] 表示节点i的next指针是多少 
//idx 存储当前已经用到了哪个点 
int head,e[N],ne[N],idx;

//初始化 
void init()
{
    head=-1;
    idx=0; 
} 

//在头节点后面插入节点 
void add_to_head(int x)
{
    e[idx]=x;
    ne[idx]=head;
    head=idx++;
}

//在k节点后面插入节点
void add(int k,int x)
{
    e[idx]=x;
    ne[idx]=ne[k];
    ne[k]=idx++;
}

//删除节点 
void remove(int k)
{
    ne[k]=ne[ne[k]];
}


int main()
{
    int m;
    cin>>m;
    init();
	
    while(m--){
        int k,x;
        char op;
		
        cin>>op;
        if(op=='H'){
            cin>>x;
            add_to_head(x);
        }
        else if(op=='D'){
            cin>>k;
            if(!k)  head=ne[head];
            remove(k-1);
        }
        else{
            cin>>k>>x;
            add(k-1,x);
        }
    }
	
	for(int i=head;i!=-1;i=ne[i]) 
        cout<<e[i]<<' ';

	return 0;
}

2.2 双链表

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int m;
int e[N],l[N],r[N],idx;

//初始化
void init()
{
    r[0]=1,l[1]=0;
    idx=2;
} 

//在第k个点左右插入一个点
void add(int k,int x)
{
    e[idx]=x;
    r[idx]=r[k],l[idx]=k;
    l[r[k]]=idx,r[k]=idx++;
}

//删除第k个点
void removes(int k)
{
    r[l[k]]=r[k];
    l[r[k]]=l[k];
}


int main()
{
    init();
	
    cin>>m;
	
    while(m--){
        string op;
        int k,x;
        cin>>op;
		
        if(op=="L"){
            cin>>x;
            add(0,x);
        }
        else if(op=="R"){
            cin>>x;
            add(l[1],x);
        }
        else if(op=="D"){
            cin>>k;
            removes(k+1);
        }
        else if(op=="IL"){
            cin>>k>>x;
            add(l[k+1],x);
        }
        else{
            cin>>k>>x;
            add(k+1,x);
        }
    }
	
    for(int i=r[0];i!=1;i=r[i]) 
        cout<<e[i]<<' ';
	
    return 0;
}

3.栈

3.1 STL容器

#include<iostream>
#include<algorithm>
#include<stack>

using namespace std;

stack<int> st;
string s;
int n;


int main()
{
    cin>>n;
	
    while(n--){
        cin>>s;
        if(s=="push"){
            int x;
            cin>>x;
            st.push(x);
        }
        else if(s=="empty"){
            if(st.size()) printf("NO\n");
            else  printf("YES\n");
        }
        else if(s=="query")
            printf("%d\n",st.top());
        else st.pop();
    }
	
    return 0;
}

3.2 数组模拟

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int n;
int st[N],tt=-1;
string s;


int main()
{
    cin>>n; 
	
    while(n--){
        cin>>s;
        if(s=="push"){
            int x;
            cin>>x;
            st[++tt]=x;
        }
        else if(s=="empty"){
            if(tt!=-1) printf("NO\n");
            else  printf("YES\n");
        }
        else if(s=="query")
            printf("%d\n",st[tt]);
		else tt--;
    }
    
    return 0;
} 

4.队列

4.1 STL容器

#include<iostream>
#include<algorithm>
#include<queue>

using namespace std;

queue<int> q;
string s;
int n;


int main()
{
    cin>>n;
	
    while(n--){
        cin>>s;
        if(s=="push"){
            int x;
            cin>>x;
            q.push(x);
        }
        else if(s=="empty"){
            if(q.size()) printf("NO\n");
            else  printf("YES\n");
        }
        else if(s=="query")
            printf("%d\n",q.front());
        else q.pop();
    }
	
    return 0;
}

4.2 数组模拟

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10; 

int n;
int q[N],hh=0,tt=-1;
string s;


int main()
{
    cin>>n;
	
    while(n--){
        cin>>s;
        if(s=="push"){
            int x;
            cin>>x;
            q[++tt]=x;
        }
        else if(s=="empty"){
            if(tt<hh) printf("YES\n");
            else  printf("NO\n");
        }
        else if(s=="pop") hh++;
        else printf("%d\n",q[hh]);
    }
	
    return 0;
}

5.树

5.1 并查集

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int fa[N];
int n,m;


int find(int x)
{
    if(fa[x]!=x) fa[x]=find(fa[x]);
    return fa[x];
}


int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) fa[i]=i;
	
    while(m--){
        int a,b;
        char op[2];
        scanf("%s%d%d",&op,&a,&b);
        if(op[0]=='M') fa[find(a)]=find(b);
        else{
            if(find(a)==find(b)) printf("Yes\n");
            else  printf("No\n");
        }
    }
	
    return 0;
}

5.2 Trie树

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

//下标是0的点,既是根结点,又是空节点
//idx是节点,son[p][u]为指向下一个节点的指针 
int son[N][26],cnt[N],idx=0; 
char str[N];

//插入节点
void insert(char str[])
{
    int p=0;
    for(int i=0;str[i];i++){
        int u=str[i]-'a';
        if(!son[p][u]) son[p][u]=++idx;
        p=son[p][u];
    }
    cnt[p]++;
} 

//查询节点
int query(char str[])
{
    int p=0;
    for(int i=0;str[i];i++){
        int u=str[i]-'a';
        if(!son[p][u]) return 0;
        p=son[p][u];
    }
    return cnt[p];
} 


int main()
{
    int n;
    scanf("%d",&n);
	
    while(n--){
        char op[2];
        scanf("%s%s",&op,&str);
        
        if(op[0]=='I') insert(str);
        else printf("%d\n",query(str));
    }
	
    return 0;
} 

6.图

6.1 邻接矩阵

#include<iostream>
#include<algorithm>

using namespace std;

const int N=510,INF=1e9+7;

int g[N][N];
int n,m;


int main()
{
    cin>>n>>m;
    fill(g[0],g[0]+N*N,INF);
	
    while(m--){
        int a,b,c;
        cin>>a>>b>>c;
        
        //有向图
        g[a][b]=min(g[a][b],c);
        //无向图
        g[a][b]=g[b][a]=min(g[a][b],c);
    }
	
    return 0;
}

6.2 邻接表

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10,INF=1e9+7;

int h[N],e[N],ne[N],w[N],idx;
int n,m;

//添加节点
void add(int a,int b,int c)
{
    e[idx]=b;
    w[idx]=c;
    ne[idx]=h[a];
    h[a]=idx++;
}


int main()
{
    scanf("%d%d",&n,&m);
    fill(h,h+N,-1);
	
    while(m--){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
		
        //有向图
        add(a,b,c);
        //无向图
        add(a,b,c),add(b,a,c);
    }
	
    return 0;
} 

7.C++ STL容器及函数(只列出较为常用的)

7.1 常用函数*

#include<iostream>
#include<algorithm>        //头文件

using namespace std;


int main()
{
    //1.max()、min()、abs()函数
    int a = 3, b = 4;
    //求最大值
    int Max = max(a,b);
    //求最小值
    int Min = min(a,b);
    //求绝对值
    int Abs = abs(-3);
    cout << Max << Min << Abs;
    
    //2.交换函数:swap()
    int a = 3, b = 4;
    swap(a,b);
	
    //3.排序函数:sort()
    int a[5] = {55,44,33,22,11};
    sort(a,a+5);
    for(int i = 0; i < 5; i++) 
        cout << a[i] << ' ';
        
    //4.填充函数:fill() (很多人都用memset,但是我就喜欢fill)
    int a[5] = {11,33,22};
    fill(a+3,a+5,9999);								
    for(int i = 0; i < 5; i++) 
        cout << a[i] << ' ';
    
    //5.翻转函数:reverse()
    int a[5] = {11,22,33,44,55};
    reverse(a,a+5);
    for(int i = 0; i < 5; i++) 
        cout << a[i] << ' ';
        
    return 0;
}

7.2 vector(动态数组)

#include<iostream>
#include<algorithm>
#include<vector>           //头文件

using namespace std;

//初始化
//方式一:初始化一维可变长数组
vector<int> c; //定义了一个名为num的存int数据的一维数组
vector<double> c;//定义了一个名为num的存double数据的一维数组
vector<node> c;//node是结构体类型
 
//方式二:初始化二维可变长数组
vector<int> c[5];//定义可变长二维数组
//注意:行是不可变的(只有5行),而列可变可以在指定行添加元素
//第一维固定长度为5,第二维长度可以改变
 
//方式三:初始化二维均可变长数组
vector<vectot<int> > c;//定义一个行和列均可变的二维数组


int main()
{
    //访问
    //方式一:单个访问,假设num数组中已经有了5个元素
    cout<<c[4]<<"\n";  //输出第五个数据
    //一二维可变数组和普通数组的访问方法一样
 
    //方式二:遍历
    for(int i=0;i<c.size();i++)
        cout<<c[i]<<" ";
 
    //方式三:智能指针
    for(auto i : c)
        cout<<i<<" ";
        
    return 0;
}
---
相关方法函数如下:c指定为数组名称

代码	含义
c.front()	返回第一个数据
c.back()	返回最后一个数据
c.push_back(element)	在尾部加一个数据 O(1)
c.pop_back()	删除最后一个数据 O(1)
c.size()	返回实际数据个数(unsigned类型) O(1)
c.clear()	清除元素个数 O(N),N为元素个数
c.resize(n,v)	改变数组大小为n,n个空间数值赋为v,如果没有默认赋值为0
c.insert(it,x)	
向任意迭代器it插入一个元素x O(N),

例:c.insert(c.begin()+2,-1) 将-1插入c[2]的位置

c.erase(first,last)	删除[first,last)的所有元素
c.begin()	返回首元素的迭代器(通俗来说就是地址)
c.end()	返回最后一个元素后一个位置的迭代器(地址)
c.empty()	判断是否为空,为空返回真,反之返回假
注意: end()返回的是最后一个元素的后一个位置的地址,不是最后一个元素的
---

7.3 stack(栈)

#include<iostream>
#include<algorithm>
#include<stack>           //头文件

using namespace std;

//初始化
stack<int> st;
stack<string> st;
stack<node> st;//node是结构体类型


int main()
{
    //访问函数
    push()	压栈,增加元素 O(1)
    pop()	移除栈顶元素 O(1)
    top()	取得栈顶元素(但不删除)O(1)
    empty()	检测栈内是否为空,空为真 O(1)
    size()	返回stack内元素的个数 O(1)
        
    return 0;
}

7.4 queue(队列)

#include<iostream>
#include<algorithm>
#include<queue>           //头文件

using namespace std;

//普通队列初始化
queue<int> q;
queue<string> q;
queue<node> q;//node是结构体类型

//优先队列初始化定义
priority_queue<int> q;
//优先队列设置优先级
priority_queue<int, vector<int>, greater<int> > q;
//最后两个>之间要有空格,旧版c++编译器会把">>"当成右移符!!!


int main()
{
    //普通队列访问函数
    front()	返回队首元素 O(1)
    back()	返回队尾元素 O(1)
    push()	尾部添加一个元素副本 进队O(1)
    pop()	删除第一个元素 出队 O(1)
    size()	返回队列中元素个数,返回值类型unsigned int O(1)
    empty()	判断是否为空,队列为空,返回true O(1)
    
    //优先队列访问函数
    top()	访问队首元素
    push()	入队
    pop()	堆顶(队首)元素出队
    size()	队列元素个数
    empty()	是否为空
    注意没有clear()!	不提供该方法
    优先队列只能通过top()访问队首元素(优先级最高的元素)
    
    //注:栈的取第一个元素为top();而普通队列的为front();优先队列为top();
        
    return 0;
}

7.5 pair

#include<iostream>
#include<algorithm>

using namespace std;

//初始化

pair<string,int>p("wangyaqi",1);//带初始值的
pair<string,int>p;//不带初始值的


int main()
{
    //访问函数
    pair<int,int>p[20];
    for(int i=0;i<20;i++){
        //和结构体类似,first代表第一个元素,second代表第二个元素
        cout<<p[i].first<<" "<<p[i].second;
    }
        
    return 0;
}

7.6 string字符串

#include<iostream>
#include<algorithm>
#include<string>       //头文件(可写可不写,iostream里自带)

using namespace std;

//定义
string s;


int main()
{
    //使用操作
    for(int i=0;i<s.size();i++) 
        cout<<s[i]<<" ";
    
    //拼接
    string s1;
    string s2;
    s1 = "123";
    s2 = "456";
    string s = s1 + s2;
    cout<<s;   //123456
    
    return 0;
}

三、搜索和图论

1.DFS深度优先搜索

1.1 基础深搜

#include<iostream>
#include<algorithm> 

using namespace std;

const int N=10;

int path[N];
bool st[N];
int n;


void dfs(int u)
{
    if(u==n){
        for(int i=0;i<n;i++) printf("%d ",path[i]);
        printf("\n");
        return;
    }
	
    for(int i=1;i<=n;i++){
        if(!st[i]){
            path[u]=i;
            st[i]=true;
            dfs(u+1);
            st[i]=false;
        }
    }
}


int main()
{
    cin>>n;
	
    dfs(0);
	
    return 0;
}
#include<iostream>
#include<algorithm>

using namespace std;

const int N=20;

bool col[N],dg[N],udg[N];
char g[N][N];
int n;


void dfs(int u)
{
    if(u==n){
        for(int i=0;i<n;i++) puts(g[i]);
        puts("");
        return;
    }
	
    for(int i=0;i<n;i++){
        if(!col[i]&&!dg[u+i]&&!udg[n-u+i]){
            g[u][i]='Q';
            col[i]=dg[u+i]=udg[n-u+i]=true;
            dfs(u+1);
            col[i]=dg[u+i]=udg[n-u+i]=false;
            g[u][i]='.';
        }
    } 
}

int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            g[i][j]='.';
	
    dfs(0);
	
    return 0;
}

1.2 图的深搜

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int h[N],e[2*N],ne[2*N],idx;
bool st[N];
int n;

int ans=N; 

//邻接表存储图 
void add(int a,int b)
{
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}

//以u为根的子树中点的数量 
int dfs(int u)
{
    st[u]=true;
    int sum=1,res=0;
    //sum存当前子树节点节点总个数 
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(!st[j]){
            int s=dfs(j);     
            //搜索子树节点个数并累加到s中 
            res=max(res,s);
            //更新res值 
            sum+=s;
            //累加节点u的子树节点 
        }
    }
    //res存当前子树节点最大值 
    res=max(res,n-sum);
    //ans存所有节点的res最小值(重心) 
    ans=min(ans,res);
    //返回子树节点总数 
    return sum;
}


int main()
{
    fill(h,h+N,-1);
	
    cin>>n;
    for(int i=0;i<n-1;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b),add(b,a);
    }
	
    dfs(1);
	
    cout<<ans<<endl;
	
    return 0;
} 

2.BFS广度优先搜索

2.1 基础搜索

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

typedef pair<int,int> PII;

const int N=110;

int g[N][N],d[N][N];
PII q[N*N];
int n,m;

int s[2][4]={
    0,0,1,-1,
    1,-1,0,0
};


int bfs()
{
    int hh=0,tt=0;
    q[0]={0,0};
	
    fill(d[0],d[0]+N*N,-1);
    d[0][0]=0;
	
    while(hh<=tt){ 
        PII t=q[hh++];
        for(int i=0;i<4;i++){
            int x=t.first+s[0][i];
            int y=t.second+s[1][i];
            if(x>=0&&x<n&&y>=0&&y<m&&g[x][y]==0&&d[x][y]==-1){
                d[x][y]=d[t.first][t.second]+1;
                q[++tt]={x,y};
            }
        }
    }
	
    return d[n-1][m-1];
}


int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            cin>>g[i][j];

	
    cout<<bfs()<<endl;
	
    return 0;
} 

2.2 图的广搜

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int h[N],e[N],ne[N],idx;
int q[N],d[N];
int n,m;

//邻接表存储图 
void add(int a,int b)
{
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}


int bfs()
{
    int hh=0,tt=0;
    fill(d,d+N,-1);
    q[0]=1,d[1]=0;
	//数组q模拟队列 
    while(hh<=tt){
        int t=q[hh++];
        for(int i=h[t];i!=-1;i=ne[i]){
            int j=e[i];
            if(d[j]==-1){
                d[j]=d[t]+1;
                q[++tt]=j;
            }
        }
    }
    //d[n]记录路径长度+判断
    return d[n];
}


int main()
{
    cin>>n>>m;
    //fill填充h数组
    fill(h,h+N,-1);
	
    for(int i=0;i<m;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
    }
	
    cout<<bfs()<<endl;
	
    return 0;
}

3.最短路径算法

3.1 朴素Dijkstra最短路(不存在负权边)

#include<iostream>
#include<algorithm>

using namespace std;

const int N=510,INF=1e9+7;

int g[N][N];
int dist[N];
bool st[N];
int n,m;


int dijkstra()
{
    fill(dist,dist+N,INF);
    dist[1]=0;
	
    for(int i=0;i<n;i++){
        int t=-1;
        for(int j=1;j<=n;j++)
            if(!st[j]&&(t==-1||dist[t]>dist[j]))
                t=j;
        for(int j=1;j<=n;j++)
            dist[j]=min(dist[j],dist[t]+g[t][j]);
        st[t]=true;
    }
	
    return dist[n];
}


int main()
{
    cin>>n>>m;
    fill(g[0],g[0]+N*N,INF);
	
    while(m--){
        int a,b,c;
        cin>>a>>b>>c;
        g[a][b]=min(g[a][b],c);
    }
	
    int t=dijkstra();
	
    if(t==INF) printf("-1");
    else printf("%d",dist[n]);
	
    return 0;
}

3.2 堆优化Dijkstra最短路

#include<iostream>
#include<algorithm>
#include<queue>

using namespace std;

const int N=1e6+10,INF=1e9+7;

typedef pair<int,int> PII;

int h[N],w[N],e[N],ne[N],idx;
int dist[N],n,m;
bool st[N];


void add(int a,int b,int c)
{
    w[idx]=c;
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}


int dijkstra()
{
    fill(dist,dist+N,INF);
    dist[1]=0;
	
    priority_queue<PII,vector<PII>,greater<PII> > heap;
    heap.push({0,1});
	
    while(heap.size()){
        PII t=heap.top();
        heap.pop();
		
        int ver=t.second,distance=t.first;
        if(st[ver]) continue;
        st[ver]=true;
		
        for(int i=h[ver];i!=-1;i=ne[i]){
            int j=e[i];
            if(dist[j]>distance+w[i]){
                dist[j]=distance+w[i];
                heap.push({dist[j],j});
            }
        }
    }
	
    if(dist[n]==INF) return -1;
    return dist[n];
}


int main()
{
    scanf("%d%d",&n,&m);
    fill(h,h+N,-1);

    while(m--){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
    }
	
    printf("%d",dijkstra());
	
    return 0;
}

3.3 bellman-ford最短路(有边数限制)

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N=510,M=10010,INF=1e9+7;

int dist[N],backup[N];
int n,m,k;

struct Edge{
    int a,b,w;
}edges[M];


void bellman_ford()
{
    fill(dist,dist+N,INF);
    dist[1]=0;
	
    for(int i=0;i<k;i++){
        memcpy(backup,dist,sizeof dist);
        for(int j=0;j<m;j++){
            int a=edges[j].a,b=edges[j].b,w=edges[j].w;
            dist[b]=min(dist[b],backup[a]+w);
        }
    }
}


int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=0;i<m;i++){
        int a,b,w;
        scanf("%d%d%d",&a,&b,&w);
        edges[i]={a,b,w};
    }
	
    bellman_ford();
	
    if(dist[n]>INF/2) printf("impossible");
    else  printf("%d",dist[n]);
	
    return 0;
}

3.4 spfa最短路(存在负权边)

#include<iostream>
#include<algorithm>
#include<queue>

using namespace std;

const int N=1e5+10,INF=1e9+7;

int h[N],e[N],ne[N],w[N],idx;
int dist[N],n,m;
bool st[N];


void add(int a,int b,int c)
{
    e[idx]=b;
    w[idx]=c;
    ne[idx]=h[a];
    h[a]=idx++;
}


void spfa()
{
    fill(dist,dist+N,INF);
    dist[1]=0;
	
    queue<int> q;
    q.push(1);
    st[1]=true;
	
    while(q.size()){
        int t=q.front();
        q.pop();
        st[t]=false;
		
        for(int i=h[t];i!=-1;i=ne[i]){
            int j=e[i];
            if(dist[j]>dist[t]+w[i]){
                dist[j]=dist[t]+w[i];
                if(!st[j]){
                    q.push(j);
                    st[j]=true;	
                } 
            } 
        }
    }
}


int main()
{
    scanf("%d%d",&n,&m);
    fill(h,h+N,-1);
	
    while(m--){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
    }
	
    spfa();
	
    if(dist[n]==INF) printf("impossible");
    else  printf("%d",dist[n]);
	
    return 0;
} 

3.5 Floyd最短路(多源)

#include<iostream>
#include<algorithm>

using namespace std;

const int N=510,INF=1e9+7;

int g[N][N];
int n,m,k;


void floyd()
{
    for(int p=1;p<=n;p++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                g[i][j]=min(g[i][j],g[i][p]+g[p][j]);
}


int main()
{
    cin>>n>>m>>k;
    fill(g[0],g[0]+N*N,INF);
    for(int i=1;i<=n;i++) g[i][i]=0; 
	
    while(m--){
        int a,b,c;
        cin>>a>>b>>c;
        g[a][b]=min(g[a][b],c);
    }
	
    floyd();
	
    while(k--){
        int a,b;
        cin>>a>>b;
        if(g[a][b]>=1e6) printf("impossible\n");
        else  printf("%d\n",g[a][b]);
    }
	
    return 0;
} 

4.最小生成树

4.1 Prim算法

#include<iostream>
#include<algorithm>

using namespace std;

const int N=510,INF=1e9+7;

int g[N][N],dist[N];
bool st[N];
int n,m;


int prim()
{
    //初始化dist数组 
    fill(dist,dist+N,INF);
	
    int res=0;
    for(int i=0;i<n;i++){
        //找到距离集合最小权的边并赋予t 
        int t=-1;
        for(int j=1;j<=n;j++)
            if(!st[j]&&(t==-1||dist[t]>dist[j]))
                t=j;
                
        //把t加到集合里 
        st[t]=true;
        
        //i!=0,把边加到res里 
        if(i){
            //如果最小值为INF,则无边到集合中 
            if(dist[t]==INF) return INF;
            res+=dist[t];
        }
        
        //更新节点到集合的最短距离 
        for(int j=1;j<=n;j++)
            dist[j]=min(dist[j],g[t][j]);
    }
	
    return res;
}


int main()
{
    scanf("%d%d",&n,&m);
    fill(g[0],g[0]+N*N,INF);
	
    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=prim();
	
    if(t==INF) printf("impossible");
    else  printf("%d",t);
	
    return 0;
} 

4.2 Kruskal算法

#include<iostream>
#include<algorithm> 

using namespace std;

const int N=2e5+10;

int n,m;
int p[N];

struct Edge{
    int a,b,w;
}edges[N];

bool cmp(Edge a,Edge b){
    return a.w<b.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,w;
        scanf("%d%d%d",&a,&b,&w);
        edges[i]={a,b,w};
    }
	
    sort(edges,edges+m,cmp);
	
    for(int i=1;i<=n;i++) p[i]=i;
	
    int sum=0,ans=0;
    for(int i=0;i<m;i++){
        int a=edges[i].a,b=edges[i].b,w=edges[i].w;
        a=find(a),b=find(b);
        if(a!=b){
            p[a]=b;
            sum+=w;
            ans++;
        }
    }
	
    if(ans<n-1) printf("impossible");
    else  printf("%d",sum);
	
    return 0;
}

5.二分图

5.1 染色法判定

#include<iostream> 
#include<algorithm>

using namespace std;

const int N=1e5+10,M=2*N;

int h[N],e[M],ne[M],idx;
int color[N];
int n,m;


void add(int a,int b)
{
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}


bool dfs(int u,int c)
{
    color[u]=c;
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(!color[j]&&!dfs(j,3-c)) return false;
        if(color[j]==c) return false;
    }
    return true;
}


int main()
{
    scanf("%d%d",&n,&m);
    fill(h,h+N,-1);
	
    while(m--){
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b),add(b,a);
    }
	
    bool flag=true;
    for(int i=1;i<=n;i++){
        if(!color[i]&&!dfs(i,1)){
            flag=false;
            break;
        }
    }
	
    if(flag) printf("Yes");
    else  printf("No");
	
    return 0;
}

5.2 匈牙利算法匹配

#include<iostream>
#include<algorithm>

using namespace std;

const int N=510,M=1e5+10;

int h[N],e[M],ne[M],idx;
int match[N];
int n1,n2,m;
bool st[N];


void add(int a,int b)
{
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}


bool find(int x)
{
    for(int i=h[x];i!=-1;i=ne[i]){
        int j=e[i];
        if(!st[j]){
            st[j]=true;
            if(!match[j]||find(match[j])){
                match[j]=x;
                return true;
            }
        }
    }
    return false;
}


int main()
{
    scanf("%d%d%d",&n1,&n2,&m);
    fill(h,h+N,-1);
	
    while(m--){
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
    }
	
    int res=0;
    for(int i=1;i<=n1;i++){
        fill(st,st+N,false);
        if(find(i)) res++;
    }
    printf("%d",res);
	
    return 0;
} 

四、数论

1.质数(素数)

1.1 试除法求质数

#include<iostream>
#include<algorithm>

using namespace std;


bool prime(int x)
{
    if(x<2) return false;
    
    for(int i=2;i<=x/i;i++)
        if(x%i==0) 
            return false;

    return true;
}


int main()
{
    int n;
    cin>>n;
    
    while(n--){
        int x;
        cin>>x;
        if(prime(x)) printf("Yes\n");
        else  printf("No\n");
    }
	
    return 0;
}

1.2 分解质因数

#include<iostream>
#include<algorithm>

using namespace std;


int main()
{
    int n;
    cin>>n;
	
    while(n--){
        int x;
        cin>>x;
		
        for(int i=2;i<=x/i;i++){
            if(x%i==0){
                int ans=0;
                while(x%i==0){
                    x/=i;
                    ans++;
                }
                printf("%d %d\n",i,ans);
            }
        }
		
        if(x>1) printf("%d %d\n",x,1);
		
        printf("\n");
    }

    return 0;
}

1.3 筛质数

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e6+10;

bool st[N];
int n,cnt;


void get_prime(int n)
{
    for(int i=2;i<=n;i++){
        if(!st[i]) cnt++;
        for(int j=i+i;j<=n;j+=i){
            st[j]=true;
        }
    }
}


int main()
{
    scanf("%d",&n);
	
    get_prime(n);
	
    printf("%d",cnt);
	
    return 0;
}

2. 约数(因数)

2.1 试除法求约数

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

vector<int> primes;
int n;


vector<int> prime(int x)
{
    vector<int> p;
    for(int i=1;i<=x/i;i++){
        if(x%i==0){
            p.push_back(i);
            if(x/i!=i) p.push_back(x/i);
        }
    }
    sort(p.begin(),p.end()); 
    return p;
}


int main()
{
    cin>>n;
	
    while(n--){
        int x;
        cin>>x;
		
        primes=prime(x);
        for(int i=0;i<primes.size();i++) printf("%d ",primes[i]);
        printf("\n");
    }
	
    return 0;
}

2.2 约数个数

#include<iostream>
#include<algorithm>
#include<unordered_map> 

using namespace std;

const int mod=1e9+7;


int main()
{
    int n;
    cin>>n;
	
    unordered_map<int,int> primes;
    while(n--){
        int x;
        cin>>x;
		
        for(int i=2;i<=x/i;i++){
            while(x%i==0){
                x/=i;
                primes[i]++;
            }
        }
        if(x>1)  primes[x]++;
    }
	
    long long ans=1;
    for(auto t:primes) ans=ans*(t.second+1)%mod;
	
    cout<<ans<<endl;
	
    return 0;
}

2.3 约数之和

#include<iostream>
#include<algorithm>
#include<unordered_map> 

using namespace std;

const int mod=1e9+7;


int main()
{
    int n;
    cin>>n;
	
    unordered_map<int,int> primes;
    while(n--){
        int x;
        cin>>x;
        //试除法判断约数并累加 
        for(int i=2;i<=x/i;i++){
            while(x%i==0){
                x/=i;
                primes[i]++;
            }
        }
        if(x>1)  primes[x]++;
    }
	
    long long ans=1;
    for(auto t:primes){
        //t遍历哈希primes
        int p=t.first,s=t.second;
        //p为n的第k个约数,s为第k个约数的个数
        long long sum=1;
        //求(1+p1^1+p1^2+...+p1^s);
        while(s--) sum=(sum*p+1)%mod;
        //求(1+p2^1+...+p1^s)*(1+p2^1+...+p2^s)*...*(1+pk^1+...+pk^s);
        ans=ans*sum%mod;
    }
	
    cout<<ans<<endl;
	
    return 0;
}

3.大整数运算

3.1 加法

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

vector<int> A,B,C;
string a,b;


vector<int> add(vector<int> &A,vector<int> &B)
{
    if(A.size()<B.size()) return add(B,A);
    
    vector<int> C;
    int t=0;
    
    for(int i=0;i<A.size()||i<B.size();i++){
        if(i<A.size()) t+=A[i];
        if(i<B.size()) t+=B[i];
        C.push_back(t%10);
        t/=10;
    }
    
    if(t) C.push_back(1);
    
    return C;
}


int main()
{
    cin>>a>>b;
    for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
    for(int i=b.size()-1;i>=0;i--) B.push_back(b[i]-'0');
	
    C=add(A,B);
	
    for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
    
    return 0;
}

3.2 减法

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

vector<int> A,B,C;
string a,b;


bool cmp(vector<int> &A,vector<int> &B)
{
    if(A.size()!=B.size()) return A.size()>B.size();
    
    for(int i=A.size()-1;i>=0;i--){
        if(A[i]!=B[i])
            return A[i]>B[i];
    }
    
    return true;
}


vector<int> sub(vector<int> &A,vector<int> &B)
{
    vector<int> c;
    
    for(int i=0,t=0;i<A.size();i++){
        t=A[i]-t;
        if(i<B.size()) t-=B[i];
        c.push_back((t+10)%10);
        t<0?t=1:t=0;
    }
    
    while(c.size()>1&&c.back()==0) c.pop_back();
    
    return c;
}


int main()
{
    cin>>a>>b;
    for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
    for(int i=b.size()-1;i>=0;i--) B.push_back(b[i]-'0')

    if(cmp(A,B)){
        C=sub(A,B);
        for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
    }
    else{
        C=sub(B,A);
        for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
    }
    
    return 0;
}

3.3 乘法

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

vector<int> A,C;
string a;
int b;


vector<int> mul(vector<int> &A,int b)
{
    vector<int> c;
    int t=0;
    
    for(int i=0;i<A.size()||t;i++){
        if(i<A.size()) t+=A[i]*b;
        c.push_back(t%10);
        t/=10;
    }
    
    return c;
}


int main()
{
    cin>>a>>b;
    for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');

    C=mul(A,b);

    for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
    
    return 0;
}

3.4 除法

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

string a;
vector<int> A;
int B,r;


vector<int> div(vector<int> &A,int b)
{
    vector<int> C;
    
    for(int i=A.size()-1;i>=0;i--){
        r=r*10+A[i];
        C.push_back(r/b);
        r%=b;
    }
    
    reverse(C.begin(),C.end());
    while(C.size()>1&&C.back()==0) C.pop_back();
    
    return C;
}


int main()
{
    cin>>a>>B;
    for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');

    vector<int> C=div(A,B);

    for(int i=C.size()-1;i>=0;i--) cout<<C[i];

    cout<<endl<<r<<endl;

    return 0;
}

4.最大公约数(最小公倍数)

4.1 欧几里得算法(辗转相除法)

#include<iostream>
#include<algorithm>

using namespace std;


int gcd(int a,int b){
    return b?gcd(b,a%b):a;
}


int main()
{
    int n;
    cin>>n;
	
    while(n--){
        int a,b;
        cin>>a>>b;
		
        //最大公约数
        printf("%d\n",gcd(a,b));
        //最小公倍数
        printf("%d\n",a*gcd(a,b)/b);
    }
	
    return 0;
}

4.2 扩展欧几里得算法

#include<iostream>
#include<algorithm>

using namespace std;

// 公式ax+by=gcd(ai,bi)
int exgcd(int a,int b,int &x,int &y){
    if(!b){
        x=1,y=0;
        return a;
    }
    int d=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}


int main()
{
    int n;
    scanf("%d",&n);
	
    while(n--){
        int a,b,x,y;
        scanf("%d%d",&a,&b);
        exgcd(a,b,x,y);
        printf("%d %d\n",x,y);
    }
	
    return 0;
}

5.快速幂

5.1 基础快速幂

#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;


LL k(LL a,LL b,LL mod)
{
    LL sum=1;
    while(b){
        if(b&1) sum=sum*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return sum%mod;
}


int main()
{
    int n;
    scanf("%d",&n);
	
    while(n--){
        LL a,b,p;
        scanf("%lld%lld%lld",&a,&b,&p);
        printf("%lld\n",k(a,b,p));
    }
	
    return 0;
}

5.2 快速幂求逆元

#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;


LL k(LL a,LL b,LL mod)
{
    LL sum=1;
    while(b){
        if(b&1) sum=sum*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return sum%mod;
}


int main()
{
    int n;
    scanf("%d",&n);
	
    while(n--){
        LL a,p,t;
        scanf("%lld%lld",&a,&p);
        if(a%p) printf("%lld\n",k(a,p-2,p));
        else  printf("impossible\n");
    }
	
    return 0;
}

5.3 矩阵快速幂

#include<iostream>
#include<algorithm>

using namespace std;

//定义矩阵结构体
struct Matrix
{
    int a[3][3];
    Matrix() memset(a,0,sizeof(a));
    //矩阵乘法
    Matrix operator*(const Matrix &b) const
    {
        Matrix res;
        for(int i=1; i<=2; i++)
            for(int j=1; j<=2; j++)
                for(int k=1; k<=2; k++)
                    res.a[i][j]=res.a[i][j]+a[i][k]*b.a[k][j];
        return res;
    }
};

Matrix base,ans;

//初始化base,ans
void init()
{
    //矩阵
    //[0,1]
    //[1,1]
    base.a[1][1]=0;//这个11位置一定要初始化
    base.a[2][2]=base.a[1][2]=base.a[2][1]=1;
    //初始斐波那契数列f1=1,f2=1
    ans.a[1][1]=1;
    ans.a[1][2]=1;

}
//快速幂
void qpow(int n)
{
    //传入n次幂
    while(n){
        if(n&1)ans=ans*base;//n为奇数
        base=base*base;
        n>>=1;// n/=2
    }
}

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF){
        init();//每次初始化矩阵
        qpow(n-2);//快速幂优化
        cout<<ans.a[1][2]<<endl;
    }

    return 0;
}

6.组合数

6.1 普通递推

#include<iostream>
#include<algorithm> 

using namespace std;

const int N=10010,mod=1e9+7;

int n;
int c[N][N];


int main()
{
    scanf("%d",&n);
    for(int i=1;i<N;i++){
        c[i][1]=i;
        c[i][i]=1;
    }
	
    for(int i=2;i<N;i++){
        for(int j=2;j<=i;j++){
            c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
        }
    }
	
    while(n--){
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%d\n",c[a][b]);
    }
	
    return 0;
} 

6.2 C(a,b) = a!/(b-a)!*b!(预处理)

#include<iostream>
#include<algorithm> 

using namespace std;

typedef long long LL;

const int N=1e5+10,mod=1e9+7;

int n;
LL f[N],inf[N];


LL q(LL a,LL k,LL p)
{
    LL sum=1;
    while(k){
        if(k&1) sum=(LL)sum*a%p;
        a=(LL)a*a%p;
        k>>=1;
    }
    return sum;
}


int main()
{
    scanf("%d",&n);
	
    f[0]=inf[0]=1;
    for(int i=1;i<N;i++){
        f[i]=(LL)f[i-1]*i%mod;
        inf[i]=(LL)inf[i-1]*q(i,mod-2,mod)%mod;
    }
	
    while(n--){
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%d\n",(LL)f[a]*inf[a-b]%mod*inf[b]%mod);
    }
	
    return 0;
} 

6.3 C(a,b) = C(a%p,b%p)*C(a/p,b/p)(lucas定理)

#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;

int p;

//快速幂求逆元
int q(LL a,LL k,LL p)
{
    int res=1;
    while(k){
        if(k&1) res=(LL)res*a%p;
        a=(LL)a*a%p;
        k>>=1;
    }
    return res;
}

//求组合数 
int c(LL a,LL b)
{
    int sum=1;
    for(int i=1,j=a;i<=b;i++,j--){
        sum=(LL)sum*j%p;
        sum=(LL)sum*q(i,p-2,p)%p;
    }
    return sum;
}

//卢卡斯定理
int lucas(LL a,LL b)
{
    if(a<p&&b<p) return c(a,b);
    return (LL)c(a%p,b%p)*lucas(a/p,b/p)%p;
}


int main()
{
    int n;
    cin>>n;
	
    while(n--){
        LL a,b;
        cin>>a>>b>>p;
        cout<<lucas(a,b)<<endl;
    }
	
    return 0;
} 

6.4 不取模运算C(a,b)

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

const int N=5010;

int primes[N],cnt;
int sum[N]; 
bool st[N];

//线性筛法 
void get_primes(int n)
{
    for(int i=2;i<=n;i++){
        if(!st[i]) primes[cnt++]=i;
        for(int j=0;primes[j]<=n/i;j++){
            st[primes[j]*i]=true;
            if(i%primes[j]==0) break;
        }
    }
}

//求a!里p因子的个数 
int get(int n,int p)
{
    int res=0;
    while(n){
        res+=n/p;
        n/=p;
    }
    return res;
}

//高精度乘法 
vector<int> mul(vector<int> a,int b)
{
    vector<int> c;
    int t=0;
	
    for(int i=0;i<a.size();i++){
        t+=a[i]*b;
        c.push_back(t%10);
        t/=10;
    }
	
	while(t){
        c.push_back(t%10);
        t/=10;
    }
	
    return c;
}


int main()
{
    int a,b;
    cin>>a>>b;
	
    get_primes(a);
	
    for(int i=0;i<cnt;i++){
        int p=primes[i];
        sum[i]=get(a,p)-get(b,p)-get(a-b,p);
    }
	
    vector<int> res;
    res.push_back(1);
	
    for(int i=0;i<cnt;i++){
        for(int j=0;j<sum[i];j++){
            res=mul(res,primes[i]);
	
    for(int i=res.size()-1;i>=0;i--) 
        printf("%d",res[i]);
	
    return 0;
}

7.博弈论

7.1 Nim博弈

#include<iostream>
#include<algorithm>

using namespace std;


int main()
{
    int n;
    scanf("%d",&n);
	
    int sum=0;
    while(n--){
        int x; 
        scanf("%d",&x);
        sum^=x;
    }
    if(sum)  printf("Yes");
    else  printf("No");
	
    return 0;
} 

7.2 集合-Nim博弈(sg函数)

#include<iostream>
#include<algorithm>
#include<unordered_set>

using namespace std;

const int N=110,M=10010;

int n,k;
int s[N],f[M];


int sg(int x)
{
    if(f[x]!=-1) return f[x];
	
    unordered_set<int> S;
    for(int i=0;i<k;i++)
        if(s[i]<=x) 
            S.insert(sg(x-s[i]));
	
    for(int i=0;;i++)
        if(!S.count(i))
            return f[x]=i;
}


int main()
{
    cin>>k;
    for(int i=0;i<k;i++) cin>>s[i];
    cin>>n;
	
    fill(f,f+M,-1);
	
    int res=0;
    while(n--){
        int a;
        cin>>a;
        res^=sg(a);
    }
	
    if(res) printf("Yes");
    else  printf("No");
	
    return 0;
}

五、动态规划

1.背包问题

1.1 01背包

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e3+10;

int n,V;
int dp[N],w[N],v[N];


int main()
{
    cin>>n>>V;
    for(int i=0;i<n;i++) cin>>v[i]>>w[i];
    
    for(int i=0;i<n;i++)
        for(int j=V;j>=v[i];j--)
            dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
            
    cout<<dp[V]<<endl;
    
    return 0;
}

1.2 完全背包

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int v[N],w[N],dp[N];
int n,m;


int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
	
    for(int i=1;i<=n;i++)
        for(int j=v[i];j<=m;j++)
            dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
	
    cout<<dp[m]<<endl;
	
    return 0;
}

1.3 多重背包

#include<iostream>
#include<algorithm>

using namespace std;

const int N=110;

int v[N],w[N],s[N];
int dp[N][N];
int n,m;


int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>v[i]>>w[i]>>s[i];
	
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            for(int k=0;k<=s[i]&&k*v[i]<=j;k++)
                dp[i][j]=max(dp[i][j],dp[i-1][j-k*v[i]]+k*w[i]);
	
    cout<<dp[n][m]<<endl;
	
    return 0;
}

1.4 分组背包

#include<iostream>
#include<algorithm>

using namespace std;

const int N=110;

int v[N][N],w[N][N],s[N];
int dp[N];
int n,m;


int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>s[i];
        for(int j=0;j<s[i];j++) cin>>v[i][j]>>w[i][j];
    }
	
    for(int i=1;i<=n;i++)
        for(int j=m;j>=0;j--)
            for(int k=0;k<s[i];k++)
                if(v[i][k]<=j)
                    dp[j]=max(dp[j],dp[j-v[i][k]]+w[i][k]);
	
    cout<<dp[m]<<endl;
	
    return 0;
}

2.线性dp

2.1 数字三角形

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e3+10;

int n;
int g[N][N];
int dp[N][N];


int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
        for(int j=0;j<=i;j++)
            cin>>g[i][j];
            
    for(int i=n-1;i>=0;i--)
        for(int j=0;j<=i;j++)
            dp[i][j]=max(dp[i+1][j+1],dp[i+1][j])+g[i][j];
    
    cout<<dp[0][0]<<endl;
    
    return 0;
}

2.2 最长上升子序列

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e3+10;

int n;
int g[N],dp[N];


int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>g[i];
    
    fill(dp,dp+n,1);
    
    int res=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<i;j++){
            if(g[i]>g[j])
                dp[i]=max(dp[i],dp[j]+1);
        }
        res=max(dp[i],res);
    }
    
    cout<<res<<endl;
    
    return 0;
}

2.3 最长公共子序列

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1010;

int m,n;
int dp[N][N];
char a[N],b[N];


int main()
{
    scanf("%d%d",&n,&m);
    scanf("%s%s",a+1,b+1);
	
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            if(a[i]==b[j])
                dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
        }
    }
	
    printf("%d",dp[n][m]);
	
    return 0;
}

2.4 最短编辑距离

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1010;

int m,n;
int dp[N][N];
char a[N],b[N];


int main()
{
	
    scanf("%d%s",&n,a+1);
    scanf("%d%s",&m,b+1);
	
    //一定要考虑边界问题!!!
    for (int i=0;i<=m;i++) dp[0][i]=i;
    for (int i=0;i<=n;i++) dp[i][0]=i;
	
    //相等即直接转换状态,不相等取所有状态的最小值再+1
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(a[i]==b[j])
                dp[i][j]=dp[i-1][j-1];
            else 
                dp[i][j]=min(min(dp[i-1][j],dp[i-1][j-1]),dp[i][j-1])+1;
        }
    }
	
    printf("%d",dp[n][m]);
	
    return 0;
}

3.进阶dp

3.1 区间dp

#include<iostream>
#include<algorithm>

using namespace std;

const int N=310;

int n;
int s[N];
int dp[N][N];


int main()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        int a;
        scanf("%d",&a);
        s[i]=s[i-1]+a;
    }
	
    for(int len=1;len<n;len++){
        for(int i=1;i+len<=n;i++){
            int l=i,r=i+len;
            dp[l][r]=1e9+7;
            for(int k=l;k<r;k++){
                dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]+s[r]-s[l-1]);
            }
        }
    }
	
    cout<<dp[1][n]<<endl;
	
    return 0;
}

3.2状态压缩dp

蒙德里安的梦想
#include<iostream>
#include<algorithm>

using namespace std;

const int N=12,M=1<<N;

long long dp[N][M];
int n,m;
bool st[M];


int main()
{
    //预处理
    while(cin>>n>>m,n||m){
        fill(dp[0],dp[0]+N*M,0);
		
        for(int i=0;i<1<<n;i++){
            st[i]=true;
            int cnt=0;
            for(int j=0;j<n;j++){
                if(i>>j&1){
                    if(cnt&1) st[i]=false;
                    cnt=0;
                }
                else cnt++;
            }
            if(cnt&1) st[i]=false;
        }
		
        dp[0][0]=1;
        for(int i=1;i<=m;i++)
            for(int j=0;j<1<<n;j++)
                for(int k=0;k<1<<n;k++)
                    if(!(j&k)&&st[j|k])
                        dp[i][j]+=dp[i-1][k];
						
        cout<<dp[m][0]<<endl;
    }
    return 0;
}
状态压缩dp求哈密顿路径
#include<iostream>
#include<algorithm>

using namespace std;

const int N=20,M=1<<N;

int n;
int w[N][N];
int dp[M][N];


int main()
{
    cin>>n;
	
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            cin>>w[i][j];
			
    fill(dp[0],dp[0]+M*N,0x3f3f3f);
	
    dp[1][0]=0;
    for(int i=0;i<1<<n;i++)
        for(int j=0;j<n;j++)
            if(i>>j&1)
                for(int k=0;k<n;k++)
                    if((i-(1<<j))>>k&1)
                        dp[i][j]=min(dp[i][j],dp[i-(1<<j)][k]+w[k][j]);
	
    cout<<dp[(1<<n)-1][n-1]<<endl;
	
    return 0;
}

3.3 树形dp

#include<iostream>
#include<algorithm>

using namespace std;

const int N=6010;

int n;
int happy[N];
int h[N],e[N],ne[N],idx;
int dp[N][2];
bool father[N];


void add(int a,int b)
{
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}


void dfs(int u)
{
    dp[u][1]=happy[u];
	
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        dfs(j);
        dp[u][0]+=max(dp[j][0],dp[j][1]);
        dp[u][1]+=dp[j][0];
    }
}


int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&happy[i]);
	
    fill(h,h+N,-1);
    for(int i=0;i<n-1;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        father[a]=true;
        add(b,a);
    }
	
    int root=1;
    while(father[root]) root++;
	
    dfs(root);
	
    printf("%d",max(dp[root][0],dp[root][1]));
	
    return 0;
}

4.记忆化搜索

4.1 斐波那契(记录值)

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int dp[N];
int n;

//斐波那契递归写法
int F(int n)
{
    if(n==0||n==1) return 1;
    if(dp[n]!=-1) return dp[N];
    else{
        dp[n]=F(n-1)+F(n-2);
        return dp[n];
    }
}


int main()
{
    cin>>n;
    
    fill(dp,dp+N,-1);
    
    F(n);
    
    return 0;
}

4.2 滑雪

#include<iostream>
#include<algorithm>

using namespace std;

const int N=310;

int n,m;
int g[N][N];
int f[N][N];

int s[2][4]={
    1,-1,0,0,
    0,0,1,-1
};


int dp(int x,int y)
{
    if(f[x][y]!=0) return f[x][y];
	
    f[x][y]=1;
    for(int i=0;i<4;i++){
        int a=x+s[0][i],b=y+s[1][i];
        if(a>=1&&a<=n&&b>=1&&b<=m&&g[a][b]<g[x][y])
            f[x][y]=max(f[x][y],dp(a,b)+1);
    }
	
    return f[x][y];
}


int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>g[i][j];
	
    int sum=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            sum=max(sum,dp(i,j));
	
    cout<<sum<<endl;
	
    return 0;
}
  • 5
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

1025hl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值