<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(" "); } 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(" "); } 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)
蓝桥总结