藍橋杯總結-常用函數及算法


<memory.h>或<string.h>

void *memset(void *s, int ch, size_t n);

 

#include <algorithm>

sort(a,a+n)排序函數,從小到大,a為數組名字,n為元素個數

sort(vector.begin(),vector.end())排序vector

只要數據類型定義了小於操作符,即可用sort

sort(a,a+n,compare)即可按照自定義順序排列,compare為比較函數,返回值為bool

lower_bound(a,a+n,x)二分查找,查找大於或等於x的第一個位置,只能查找vector<>數組,返回值為vector<>::iterator指針

    unique(vector1.begin(),vector1.end()),重排元素,使得所有值提前,返回值為重排后最后一個非重復值的后面的值的迭代器,即從返回值到vector1.end()是無意義的值,也是重復值的總數量

reverse(vector1.begin(),vector1.end()),反轉元素順序

next_permutation(p,p+n),求下一個全排列,枚舉用

 

#include <vector>   數組

定義示例:vector<int> b(5);或者vector<int> a;

賦值:b[0]=1;只有第一種定義可以這樣賦值

函數:

int size(),獲取大小

void resize(int num),改變大小

void push_back(int x),向尾部添加元素

void pop_back(),刪除最后一個元素

void clear(),清空

bool empty(),檢查是否為空

iterator insert(iterator x,y),向vector數組的x位置插入元素y,x可以為v.begin()+2

iterator erase(iterator x),刪除vector數組的x位置元素

iterator begin(),返回頭指針

iterator end(),返回尾指針

vector<>::iterator為一個可以指向其元素的指針

 

#include <set>         集合,其中不含重復元素,且其中元素已從小到大排序,從1開始

定義示例:set<int> a;

函數:

int size(),獲取大小

iterator find(x),若找到x,返回該鍵值迭代器的位置,否則,返回最后一個元素后面一個位置,即s.end()

void clear(),清空

bool empty(),檢查是否為空

iterator insert(y),向set集合插入元素y

iterator erase(iterator x),刪除set集合的值為x的元素,返回值為下一個位置的迭代器

iterator begin(),返回頭指針

iterator end(),返回尾指針

set<>::iterator為一個可以指向其元素的指針

 

#include <map>       映射,索引

         定義示例:map<string,int> month_name;

賦值:map[“July”]=7;

函數:

iterator find(y),尋找索引值為y的元素,返回指向其的指針

iterator insert(map<string,int>(“July”,7)),向map映射插入元素(“July”,7)

iterator erase(iterator x),刪除map映射的迭代器x的元素

map< string,int>::iterator l_it;;

   l_it=m.find(“July”);

   if(l_it==m.end())

        cout<<"we do not find July"<<endl;

   else  m.erase(l_it);  //delete July;

iterator begin(),返回頭指針

iterator end(),返回尾指針

map<>::iterator為一個可以指向其元素的指針

 

#include <stack>

定義示例:stack<int> s;

void push(x),將值x壓入棧

void pop(),刪除頂部元素

top(),獲得棧頂元素,但不刪除

bool empty(),檢查是否為空

int size(),獲取大小

 

#include <queue>

定義示例:queue<int> q;

void push(x),將值x入隊

void pop(),出隊

front(),獲得隊頭元素,但不刪除

bool empty(),檢查是否為空

int size(),獲取大小

 

#include <string>

string substr(int pos = 0,int n = npos) const;  //返回pos開始的n個字符組成的字符串

void swap(string &s2);                                       //交換當前字符串與s2的值

string &insert(int p0, const char *s);                //在p0位置插入字符串

string &erase(int pos = 0, int n = npos);          //刪除pos開始的n個字符,返回修改后的字符串

int find(char c, int pos = 0) const;                     //從pos開始查找字符c在當前字符串的位置

int find(const char *s,int pos = 0) const;         //從pos開始查找字符串s在當前串中的位置

 

算法:

快速排序:

void quicksort(int *a,int l,int r){

         if(l>=r)

                  return;

         int temp=a[l];                                    //哨兵

         int i=l,j=r;

         while(i<j){

                  while(i<j){                                   //從右開始往左判斷

                          if(a[j]>=temp){

                                   j--;

                          }

                          else{

                                   a[i++]=a[j];

                                   break;

                          }

                  }

                  while(i<j){                                   //從左開始往右判斷

                          if(a[i]<=temp){

                                   i++;

                          }

                          else{

                                   a[j--]=a[i];

                                   break;

                          }

                  }

         }

         a[i]=temp;                                          //將哨兵放回中間位置

         quicksort(a,l,i-1);                               //左邊排序

         quicksort(a,i+1,r);                             //右邊排序

}

 

歸並排序:

void mergesort(int *a,int l,int r,int *b){

         if(l>=r)

                  return ;

         int mid=l+r;

         mid/=2;

         mergesort(a,l,mid,b);      //左邊有序

         mergesort(a,mid+1,r,b);  //右邊有序

        

         int k=l,i=l,j=mid+1;                    //注意k的初值

         while(i<=mid&&j<=r){              //將i-mid和j-r兩組有序序列,歸並在一個有序序列中

                  if(a[i]<=a[j])

                          b[k++]=a[i++];

                  else

                          b[k++]=a[j++];

         }

         while(i<=mid)                            //將i-mid剩余的數放在最后

                  b[k++]=a[i++];

         while(j<=r)                                 //將j-r剩余的數放在最后

                  b[k++]=a[j++];

         for(k=l;k<=r;k++)                       //將b數組中的數據拷貝到原數組中

                  a[k]=b[k];

}

 

並查集:

#define N 100

int father[N];

void init() {

    for(int i=0; i<N; i++)

      father[i] = i;

}

// 合並兩個元素所在的集合

void union(int x,int y) {

    x = getfather(x);

    y = getfather(y);

    if(x!= y)

       father[x]=y;

}

// 判斷兩個元素是否屬於同一個集合

bool same(int x,int y) {

    return getfather(x)==getfather(y);

}

// 獲取根結點

int getfather(int x) {

    while(x != father[x])

      x = father[x];

    return x;

}

// 獲取根結點,是上邊函數的改進,壓縮了路徑長度

int getfather(int x) {

    if(x != father[x])

      father[x] = getfather(father[x]); // 路徑壓縮修改的是father數組

    return father[x];

}

 

二分查找:

int erfen(int *a,int l,int r,int v){        //a為待查找數組,l為下界下標,r為上界下標,v為目標值

         int mid;

         while(l<=r){

                  mid=l+r;

                  mid/=2;

                  if(a[mid]==v)   return mid;

                  else if(a[mid]>v)      r=mid-1;

                  else  l=mid+1;

         }      

         return -1;

}

 

01背包動態規划:

int f[5000];

int v[201],w[201];

 

int main(int argc, char** argv) {

         int n=0,m,i,j,mx=0;

         cin>>n>>m;

         for(i=1;i<=n;i++){

                  cin>>w[i]>>v[i];

         }

         for(i=1;i<=n;i++){

                  for(j=m;j>=w[i];j--){

                          f[j]=max(f[j],f[j-w[i]]+v[i]);

                          mx=max(mx,f[j]);

                  }

         }

         cout<<mx;

         return 0;

}

 

LIS最長上升子序列

int LIS(int *a,int n){

         int *dp=new int[n];         //存儲以i為尾的最長上升子序列長度

         int mx=0,m,i,j;

         dp[0]=1;                            //初值,第一個字符為1

         for(i=1;i<n;i++){

                  m=0;

                  for(j=0;j<i;j++){        //對當前i之前的所有元素的最長上升子序列做判斷

                          if(dp[j]>m&&a[j]<a[i]){

                                   m=dp[j];

                          }

                  }

                  dp[i]=m+1;               //最大m值再加上1

                  mx=max(mx,dp[i]); //同時判斷所有最長上升子序列長度的最大值

         }

         return mx;

}

 

LCS最長公共子序列

動態規划法:

void LCS(string str1,string str2)

{

         int x_len = str1.length();

         int y_len = str2.length();

        

         int arr[50][50] = {{0,0}};

        

         int i = 0;

         int j = 0;

         //動態規划二維矩陣

         for(i = 1; i <= x_len; i++)

         {

                  for(j = 1; j <= y_len; j++)

                  {

                          if(str1[i - 1] == str2[j - 1])

                          {

                                   arr[i][j] = arr[i - 1][j - 1] + 1;

                         }

                          else

                          {

                                   if(arr[i][j - 1] >= arr[i - 1][j])

                                   {

                                            arr[i][j] = arr[i][j - 1];

                                   }

                                   else

                                  {

                                            arr[i][j] = arr[i -1][j];

                                   }

                          }

                  }

         }

        

         //打印最長公共子序列

         stack<char> s;

        

         for(i = x_len, j = y_len; i >= 1 && j >= 1;)

         {

                  if(str1[i - 1] == str2[j - 1])

                  {

                          s.push(str1[i - 1]);

                          //cout<<str1[i - 1]<<" ";

                          i--;

                          j--;

                  }

                  else

                  {

                          //  if(arr[i][j -1] >= arr[i - 1][j])//打印兩種情況

                          if(arr[i][j -1] > arr[i - 1][j])

                          {

                                   j--;

                          }

                          else

                          {

                                   i--;

                          }

                  }

         }

         while(!s.empty()){

                  cout<<s.top();

                  s.pop();

         }

         cout << endl;

}

遞歸法:(只能求數量)

int LCS(char* x,char *y){

         if(strlen(x)==0)                  return 0;

         if(strlen(y)==0)         return 0;

        

         if(*x==*y)         return LCS(x+1,y+1)+1;

         return max(LCS(x,y+1),LCS(x+1,y));

}

 

Dijkstra最短路徑算法

#define MAX 9999999

#define NUM 6

int edge[NUM][NUM];                     //存儲兩點間距離

int dist[NUM];                                   //存儲到每個點的最短距離

int mark[NUM];                                 //標記是否已選

//n:多少個點  start:起始點   

void Dijkstra(int n,int start){

         int i,j,k=start;

         int min;

         for(i=0;i<n;i++){

                  mark[i]=0;

                  dist[i]=edge[start][i];

         }

         mark[start]=1;

         dist[start]=0;

         for(i=0;i<n;i++){

                  min=MAX;

                  for(j=0;j<n;j++){

                          if(!mark[j]&&dist[j]<min){

                                   min=dist[j];

                                   k=j;

                          }

                  }

                  mark[k]=1;

                  for(j=0;j<n;j++){

                          if(!mark[j]&&dist[j]>dist[k]+edge[k][j]){

                                   dist[j]=dist[k]+edge[k][j];

                          }

                  }

         }

}

 

Floyd

#define MAX 9999999

#define NUM 6

int edge[NUM][NUM];

int temp[NUM][NUM];

 

void Floyd(int a[NUM][NUM],int b[NUM][NUM]){

         int i,j,k;

         for(k=0;k<NUM;k++){

                  for(i=0;i<NUM;i++){

                          for(j=0;j<NUM;j++){

                                   if(k==0)

                                            b[i][j]=a[i][j];

                                   else{

                                            b[i][j]=min(b[i][j],b[i][k]+b[k][j]);

                                   }

                          }

                  }

         }      

}

 

最小生成樹(prim)最好選擇下邊Krusal算法

#define MAX  100000

#define VNUM  6                       

int edge[NUM][NUM];

int lowcost[NUM];             //記錄Vnew中每個點到V中鄰接點的最短邊

int addvnew[NUM];               //標記某點是否加入Vnew

int adjecent[NUM];            //記錄最小生成樹的邊,從adjecent[i]到i

 

void prim(int start){

         int i,j,k;

         int v,min;

         int sum=0;

         for(i=0;i<NUM;i++){

                  addvnew[i]=0;

                  adjecent[i]=start;

                  lowcost[i]=edge[start][i];

         }

         addvnew[start]=1;

         for(i=0;i<NUM-1;i++){

                  min=MAX;

                  v=-1;

                  for(j=0;j<NUM;j++){

                          if(!addvnew[j]&&min>lowcost[j]){

                                   min=lowcost[j];

                                   v=j;

                          }

                  }

                  if(v!=-1){

                          addvnew[v]=1;

                          sum+=lowcost[v];

                          for(j=0;j<NUM;j++){

                                   if(!addvnew[j]&&lowcost[j]>edge[v][j]){

                                            lowcost[j]=edge[v][j];

                                            adjecent[j]=v;

                                   }

                          }

                  }

         }

}

 

Kruskal

#define N 100

Int w[N],p[i],r[i];     //w為權值數組,p為並查集數組,r為邊權值排序數組,里邊存儲的是邊的w對應的標號

 

Int cmp(const int I,const int j){ return w[i]<w[j]; }

Int find(int x){ return p[x]==x?x:find(p[x]); }

Int Kruskal(){

         Int ans=0;

         For(int i=0;i<n;i++) p[i]=I;

         For(int i=0;i<n;i++) r[i]=I;

         Sort(r,r+m,cmp);//給邊升序排列

         For(int i=0;i<n;i++){

                  Int e=r[i]; int x=find(u[e]); int y=find(v[e]);

                  If(x!=y) { ans+=w[e]; p[x]=y; }

         }

         return ans;

}

 

測試數據

for(int i=0;i<VNUM;i++){

                  for(int j=0;j<VNUM;j++){

                          edge[i][j]=MAX;

                  }

         }

         edge[1][2]=5;

         edge[2][1]=5;

         edge[3][2]=3;

         edge[2][3]=3;

         edge[1][3]=4;

         edge[3][1]=4;

         edge[1][6]=7;

         edge[6][1]=7;

         edge[2][5]=6;

         edge[5][2]=6;

         edge[3][4]=2;

         edge[4][3]=2;

         edge[4][6]=3;

         edge[6][3]=3;

         edge[4][5]=1;

         edge[5][4]=1;

         edge[5][6]=4;

         edge[6][5]=4;

 

可重集的全排列(遞歸)

void print_permutation(int n,int P[],int A[],int cur)        //P按順序存儲待排列數,A同樣大小的臨時空間數組

{

         int i,j;

         if(cur==n){

                  for(i=0;i<n;i++) printf("%d ",A[i]);                    //可輸出可統計

                  printf("\n");

         }

         else for(i=0;i<n;i++) if(!i||P[i]!=P[i-1]){

                  int c1=0,c2=0;

                  for(j=0;j<cur;j++) if(A[j]==P[i])c1++;

                  for(j=0;j<n;j++) if(P[i]==P[j])c2++;

                  if(c1<c2){

                          A[cur]=P[i];

                          print_permutation(n,P,A,cur+1);

                  }

         }

}

next_permutation(p,p+n),求下一個全排列

 

二進制法求子集

void print_submet(int n,int s){                 //打印一個子集

         for(int i=0;i<n;i++)                            

                  if(s&(1<<i)) printf("%d ",i);      //s=101時,代表子集{0,2}

         printf("\n");

}

int main() {

         int n=7;                                                //代表集合{0,1,2,3,4,5,6},二進制表示

         for(int i=0;i<(1<<n);i++)                    //枚舉所有子集

                  print_submet(n,i);

         return 0;

}

 

快速求冪

int pow3(int x,int n){

         if(n==0)                                       //任何數的0次冪都是1

                  return 1;

         else{                                            //把尾部的0全部去除

                  while((n&1)==0){

                          n>>=1;

                          x*=x;

                  }

         }

         int res=x;                                    //后邊的都不明白

         n>>=1;

         while(n!=0){

                  x*=x;

                  if((n&1)!=0)

                          res*=x;

                  n>>=1;

         }

         return res;

}

 

輾轉相除法求最大公約數:

int gcd(int a,int b){

         int temp;

         while(a%b!=0){

                  temp=a;

                  a=b;

                  b=temp%b;

         }

         return b;

}

輾轉相除法最大公倍數:

int lcm(int a,int b){

         int a1=a,b1=b,temp;

         while(a%b!=0){

                  temp=a;

                  a=b;

                  b=temp%b;

         }

         return a1/b*b1;

}

 

有重復元素的全排列:
例如:有k個元素,其中第i個元素有ni個,求全排列個數。

X=n!/(n1!*n2!......nk!)

 

可重復選擇的組合:

有N個不同元素,每個元素可以選多次,一共選k個元素,有多少種選法?

C(n+k-1,k)

分析詳見P319

 

楊輝三角:

任意一行的所有元素

C[0]=1;

For(int i=1;i<=n;i++)         C[i]=C[i-1]*(n-i+1)/i

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM