我的ACM算法模板
acm 算法模板 适合初学者使用
三角形面积计算 (1)字典树模板 (2)求线段所在直线 (5)求外接圆 (5)求内接圆 (6)判断点是否在直线上 (8)简单多边形面积计算公式 (8)stein算法求最大共约数 (9)最长递增子序列模板——o(nlogn算法实现) (9)判断图中同一直线的点的最大数量 (10)公因数和公倍数 (12)已知先序中序求后序 (12)深度优先搜索模板 (13)匈牙利算法——二部图匹配BFS实现 (15)带输出路径的prime算法 (17)prime模板 (18)kruskal模板 (19)dijsktra (22)并查集模板 (23)高精度模板 (24)三角形面积计算//已知三条边和外接圆半径,公式为s = a*b*c/(4*R)double GetArea(double a, double b, double c, double R){return a*b*c/4/R;}//已知三条边和内接圆半径,公式为s = prdouble GetArea(double a, double b, double c, double r){return r*(a+b+c)/2;}//已知三角形三条边,求面积double GetArea(doule a, double b, double c){double p = (a+b+c)/2;return sqrt(p*(p-a)*(p-b)*(p-c));}//已知道三角形三个顶点的坐标struct Point{double x, y;Point(double a = 0, double b = 0){x = a; y = b;}};double GetArea(Point p1, Point p2, Point p3){double t =-p2.x*p1.y+p3.x*p1.y+p1.x*p2.y-p3.x*p2.y-p1.x*p3.y+p2.x*p3.y;if(t < 0) t = -t;return t/2;}字典树模板#include <stdio.h>#include <string.h>#include <memory.h>#define BASE_LETTER 'a'#define MAX_TREE 35000#define MAX_BRANCH 26struct{int next[MAX_BRANCH]; //记录分支的位置int c[MAX_BRANCH]; //查看分支的个数int flag; //是否存在以该结点为终止结点的东东,可以更改为任意的属性}trie[MAX_TREE];int now;void init(){now = 0;memset(&trie[now], 0, sizeof(trie[now]));now ++;}int add (){memset(&trie[now], 0, sizeof(trie[now]));return now++;}int insert( char *str){int pre = 0, addr;while( *str != 0 ){addr = *str - BASE_LETTER;if( !trie[pre].next[addr] )trie[pre].next[addr] = add();trie[pre].c[addr]++;pre = trie[pre].next[addr];str ++;}trie[pre].flag = 1;return pre;}int search( char *str ){int pre = 0, addr;while( *str != 0 ){addr = *str - BASE_LETTER;if ( !trie[pre].next[addr] )return 0;pre = trie[pre].next[addr];str ++;}if( !trie[pre].flag )return 0;return pre;}pku2001题,源代码:void check( char *str ){int pre = 0, addr;while(*str != 0){addr = *str - BASE_LETTER;if( trie[pre].c[addr] == 1) {printf("%c\n", *str);return;}printf("%c", *str);pre = trie[pre].next[addr];str ++;}printf("\n");}char input[1001][25];int main(){int i = 0,j;init();while(scanf("%s", input[i]) != EOF){getchar();insert(input[i]);i++;}for(j = 0; j < i; j ++){printf("%s ", input[j]);check(input[j]);}return 0;}求线段所在直线//*****************************线段所在的直线struct Line{double a, b, c;};struct Point{double x, y;}Line GetLine(Point p1, Point p2){//ax+by+c = 0返回直线的参数Line line;line.a = p2.y - p1.y;line.b = p1.x - p2.x;line.c = p2.x*p1.y - p1.x*p2.y;return line;}求外接圆//***************已知三角形三个顶点坐标,求外接圆的半径和坐标********************struct Point{double x, y;Point(double a = 0, double b = 0){x = a; y = b;}};struct TCircle{double r;Point p;}double distance(Point p1, Point p2){return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));}double GetArea(doule a, double b, double c){double p = (a+b+c)/2;return sqrt(p*(p-a)*(p-b)*(p-c));}TCircle GetTCircle(Point p1, Point p2, Point p3){double a, b, c;double xa,ya, xb, yb, xc, yc, c1, c2;TCircle tc;a = distance(p1, p2);b = distance(p2, p3);c = distance(p3, p1);//求半径tc.r = a*b*c/4/GetArea(a, b, c);//求坐标xa = p1.x; ya = p1.b;xb = p2.x; yb = p2.b;xc = p3.x; yc = p3.b;c1 = (xa*xa + ya*ya - xb*xb - yb*yb)/2;c2 = (xa*xa + ya*ya - xc*xc - yc*yc)/2;tc.p.x = (c1*(ya-yc) - c2*(ya-yb))/((xa-xb)*(ya-yc) - (xa-xc)*(ya-yb)); tc.p.y = (c1*(xa-xc) - c2*(xa-xb))/((ya-yb)*(xa-xc) - (ya-yc)*(xa-xb));return tc;}求内接圆struct Point{double x, y;Point(double a = 0, double b = 0){x = a; y = b;}};struct TCircle{double r;Point p;}double distance(Point p1, Point p2){return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));}double GetArea(doule a, double b, double c){double p = (a+b+c)/2;return sqrt(p*(p-a)*(p-b)*(p-c));}TCircle GetTCircle(Point p1, Point p2, Point p3){double a, b, c;double xa,ya, xb, yb, xc, yc, c1, c2, f1, f2;double A,B,C;TCircle tc;a = distance(p1, p2);b = distance(p3, p2);c = distance(p3, p1);//求半径tc.r = 2*GetArea(a, b, c)/(a+b+c);//求坐标A = acos((b*b+c*c-a*a)/(2*b*c));B = acos((a*a+c*c-b*b)/(2*a*c));C = acos((a*a+b*b-c*c)/(2*a*b));p = sin(A/2); p2 = sin(B/2); p3 = sin(C/2);xb = p1.x; yb = p1.b;xc = p2.x; yc = p2.b;xa = p3.x; ya = p3.b;f1 = ( (tc.r/p2)*(tc.r/p2) - (tc.r/p)*(tc.r/p) + xa*xa - xb*xb + ya*ya - yb*yb)/2;f2 = ( (tc.r/p3)*(tc.r/p3) - (tc.r/p)*(tc.r/p) + xa*xa - xc*xc + ya*ya - yc*yc)/2;tc.p.x = (f1*(ya-yc) - f2*(ya-yb))/((xa-xb)*(ya-yc)-(xa-xc)*(ya-yb)); tc.p.y = (f1*(xa-xc) - f2*(xa-xb))/((ya-yb)*(xa-xc)-(ya-yc)*(xa-xb));return tc;}判断点是否在直线上//**************判断点是否在直线上********************* //判断点p是否在直线[p1,p2]struct Point{double x,y;};bool isPointOnSegment(Point p1, Point p2, Point p0){//叉积是否为0,判断是否在同一直线上if((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y) != 0)return false;//判断是否在线段上if((p0.x > p1.x && p0.x > p2.x) || (p0.x < p1.x && p0.x < p2.x)) return false;if((p0.y > p1.y && p0.y > p1.y) || (p0.y < p1.y && p0.y < p2.y)) return false;return true;}简单多边形面积计算公式struct Point{double x, y;Point(double a = 0, double b = 0){x = a; y = b;}};Point pp[10];double GetArea(Point *pp, int n){//n为点的个数,pp中记录的是点的坐标int i = 1;double t = 0;for(; i <= n-1; i++)t += pp[i-1].x*pp[i].y - pp[i].x*pp[i-1].y;t += pp[n-1].x*pp[0].y - pp[0].x*pp[n-1].y;if(t < 0) t = -t;return t/2;}stein算法求最大共约数int gcd(int a,int b){if (a == 0) return b;if (b == 0) return a;if (a % 2 == 0 && b % 2 == 0) return 2 * gcd(a/2,b/2); else if (a % 2 == 0) return gcd(a/2,b);else if (b % 2 == 0) return gcd(a,b/2);else return gcd(abs(a-b),min(a,b));}最长递增子序列模板——o(nlogn算法实现)#include <stdio.h>#define MAX 40000int array[MAX], B[MAX];int main(){int count,i,n,left,mid,right,Blen=0,num;scanf("%d",&count); //case的个数while(count--){scanf("%d",&n); //每组成员的数量Blen = 0;for(i=1;i<=n;i++)scanf("%d",&array[i]); //读入每个成员for(i=1;i<=n;i++){num = array[i];left = 1;right = Blen;while(left<=right){mid = (left+right)/2;if(B[mid]<num)left = mid+1;elseright = mid-1;}B[left] = num;if(Blen<left)Blen++;}printf("%d\n",Blen);//输出结果}return 1;}判断图中同一直线的点的最大数量#include <iostream>#include <cstdio>#include <memory>using namespace std;#define MAX 1010 //最大点的个数struct point{int x,y;}num[MAX];int used[MAX][MAX*2]; //条件中点的左边不会大于1000,just equal MAX int countN[MAX][MAX*2];#define abs(a) (a>0?a:(-a))int GCD(int x, int y){int temp;if(x < y){temp = x; x = y; y = temp;}while(y != 0){temp = y;y = x % y;x = temp;}return x;}int main(){int n,i,j;int a,b,d,ans;while(scanf("%d", &n)==1){//initeans = 1;memset(used, 0, sizeof(used));memset(countN, 0, sizeof(countN));//readfor(i = 0; i < n; i++)scanf("%d%d", &num[i].x, &num[i].y);for(i = 0; i < n-1; i++){for(j = i+1; j < n; j++){b = num[j].y-num[i].y;a = num[j].x-num[i].x;if(a < 0) //这样可以让(2,3)(-2,-3)等价{a = -a; b = -b;}d = GCD(a,abs(b));a /= d;b /= d; b += 1000;//条件中点的左边不会大于1000if(used[a][b] != i+1){used[a][b] = i+1;countN[a][b] = 1;}else{countN[a][b]++;if(ans < countN[a][b])ans = countN[a][b];}}//for}//forprintf("%d\n", ans+1);}return 0;}公因数和公倍数int GCD(int x, int y){int temp;if(x < y){temp = x; x = y; y = temp;}while(y != 0){temp = y;y = x % y;x = temp;}return x;}int beishu(int x, int y){return x * y / GCD(x,y);}已知先序中序求后序#include <iostream>#include <string>using namespace std;string post;void fun(string pre, string mid){if(pre == "" || mid == "") return;int i = mid.find(pre[0]);fun(pre.substr(1,i), mid.substr(0,i));fun(pre.substr(i+1, (int)pre.length()-i-1), mid.substr(i+1, (int)mid.length()-i-1));post += pre[0];}int main(){string pre, mid;while(cin >> pre){cin >> mid;post.erase();fun(pre, mid);cout << post << endl;}return 0;}深度优先搜索模板int t; //t用来标识要搜索的元素int count; //count用来标识搜索元素的个数int data[m][n]; //data用来存储数据的数组//注意,数组默认是按照1……n存储,即没有第0行//下面是4个方向的搜索,void search(int x, int y){data[x][y] = *; //搜索过进行标记if(x-1 >= 1 && data[x-1][y] == t){count++;search(x-1,y);}if(x+1 <= n && data[x+1][y] == t){count++;search(x+1,y);}if(y-1 >= 1 && data[x][y-1] == t){count++;search(x,y-1);}if(y+1 <= n && data[x][y+1] == t){count++;search(x,y+1);}}//下面是8个方向的搜索void search(int x, int y){data[x][y] = *; //搜索过进行标记if(x-1 >= 1){if(data[x-1][y] == t){count++;search(x-1,y);}if(y-1 >= 1 && data[x-1][y-1] == t) {count++;search(x-1,y-1);}if(y+1 <= n && data[x-1][y+1] == t) {count++;search(x-1,y+1);}}if(x+1 <= n){if(data[x+1][y] == t){count++;search(x+1,y);}if(y-1 >= 1 && data[x+1][y-1] == t) {count++;search(x+1,y-1);}if(y+1 <= n && data[x+1][y+1] == t) {count++;search(x+1,y+1);}}if(y-1 >= 1 && data[x][y-1] == t){count++;search(x,y-1);}if(y+1 <= n && data[x][y+1] == t){count++;search(x,y+1);}}匈牙利算法——二部图匹配BFS实现//匈牙利算法实现#define MAX 310 //二部图一侧顶点的最大个数int n,m; //二分图的两个集合分别含有n和m个元素。
ACM 算法模板2
目录一、图论 (2)1.1.最小生成树类prim算法 (2)1.2.拓扑排序 (4)1.3.最短源路径Folyd实现 (5)1.4.关键路径实现算法 (6)1.5.二分图最大匹配的匈牙利算法 (8)1.6.并查集 (9)二、动规 (11)2.1.求最长子序列 (11)2.2.求解最长升序列长度及子序列 (12)2.3.完全背包问题 (13)2.4.0-1背包问题 (14)2.5.母函数DP算法求组合数 (15)2.6.滚动数组求回文串问题 (17)三、贪心 (18)3.1.时间安排问题 (18)3.2.求最大子段和 (19)3.3.贪心求最少非递减序列数 (20)四、数论 (21)4.1.简单求Cnk问题 (21)4.2.巧求阶乘位数 (21)4.3.线性算法求素数 (22)五、其他 (22)5.1.采用位操作递归求解示例 (22)5.2.Stack和Queue用法 (23)5.3.map使用详解 (24)5.4.字典树建立与查找 (25)5.5.KMP匹配算法 (26)5.6.后缀数组求最长连续公共子序列长度 (28)5.7.循环字符串最小位置表示及同构判断 (30)5.8.求哈夫曼树编码长度 (32)5.9.堆排序算法 (34)5.10.线段树着色问题 (35)六、附: (39)6.1.C++最值常量 (39)6.2.类型转换 (39)6.3.String常用函数举例 (39)6.4.C++常用头文件 (40)一、图论1.1.最小生成树类prim算法1.1.1下标从1开始#include<iostream>#include<cstdio>#include<algorithm>using namespace std;#define SIZE 101#define MAXSIZE 10201int n,nline;/*n 个点,nline行关系*/int in[SIZE];struct Point{int x,y;/*编号从1开始*/int v;/*根据实际情况更改类型*/}p[MAXSIZE];/*n*(n-1)/2*/int cmp(Point a,Point b){return a.v<b.v;}int prim(){int dis,count,i,j;memset(in,0,sizeof(in));in[p[1].x]=in[p[1].y]=1;dis=p[1].v;count=n-1;while(count--){/*做n-1次*/for(j=2;j<nline;j++){if((in[p[j].x]&&!in[p[j].y])||(!in[p[j].x]&&in[p[j].y])){in[p[j].x]=1;in[p[j].y]=1;dis+=p[j].v;break;}}}return dis;}int main(){int x,y,v,i;while(scanf("%d",&n)&&n){if(n==1){/*有可能输入的为1个点*/printf("0\n");continue;}nline=n*(n-1)/2+1;for(i=1;i<nline;i++){scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].v);}sort(p+1,p+nline,cmp);printf("%d\n",prim());}return 0;}1.1.2下标从0开始#include<iostream>#include<cstdio>#include<algorithm>using namespace std;#define SIZE 101#define MAXSIZE 10201int n,nline;/*n 个点,nline行关系*/int in[SIZE];struct Point{int x,y;/*编号从1开始*/int v;/*根据实际情况更改类型*/}p[MAXSIZE];/*n*(n-1)/2*/int cmp(Point a,Point b){return a.v<b.v;}int prim(){int dis,count,i,j;memset(in,0,sizeof(in));in[p[0].x]=in[p[0].y]=1;dis=p[0].v;count=n-1;while(count--){/*做n-1次*/for(j=1;j<nline;j++){if((in[p[j].x]&&!in[p[j].y])||(!in[p[j].x]&&in[p[j].y])){in[p[j].x]=1;in[p[j].y]=1;dis+=p[j].v;break;}}}return dis;}int main(){int x,y,v,i;while(scanf("%d",&n)&&n){if(n==1){/*有可能输入的为1个点*/printf("0\n");continue;}nline=n*(n-1)/2;for(i=0;i<nline;i++){scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].v);}sort(p,p+nline,cmp);printf("%d\n",prim());}return 0;}1.2.拓扑排序#include<iostream>#include<cstdio>#include<cstring>#define M 501using namespace std;int map[M][M],degree[M];int ne;/*个数*/void topo(){int i,j,k;for(i=0;i<ne;i++){j=1;while(j<=ne&°ree[j])j++;//直到一个度为零的顶点,这里不检查有多个度为零的情况//if(j>ne){break;}不是拓扑结构if(i)printf(" ");printf("%d",j);degree[j]=-1;for(k=1;k<=ne;k++){degree[k]-=map[j][k];}}printf("\n");}int main(){int a,b,i,j,nline;/*nline行*/while(scanf("%d%d",&ne,&nline)!=EOF){memset(map,0,sizeof(map));memset(degree,0,sizeof(degree));while(nline--){scanf("%d%d",&a,&b);map[a][b]=1;/*a to b*/}for(i=1;i<=ne;i++){for(j=1;j<=ne;j++){if(map[i][j])degree[j]++;}}topo();/*拓扑*/}return 0;}1.3.最短源路径Folyd实现#include<iostream>#include<cstdio>#include<cstring>#define M 201using namespace std;int n,map[M][M],start,end;void folyd(){int i,j,k;for(i=0;i<n;i++){for(j=0;j<n;j++){for(k=0;k<n;k++){if(map[j][i]==-1||map[i][k]==-1)continue;if(map[j][k]==-1||map[j][i]+map[i][k]<map[j][k]){map[j][k]=map[j][i]+map[i][k];}}}}}int main(){int nline,i,j,a,b,v;while(scanf("%d%d",&n,&nline)!=EOF){memset(map,-1,sizeof(map));for(i=0;i<n;i++){map[i][i]=0;}for(i=0;i<nline;i++){scanf("%d%d%d",&a,&b,&v);/*编号从0开始*/if(map[a][b]==-1||map[a][b]>v){//一个点到另一个有多条路map[b][a]=map[a][b]=v;}}scanf("%d%d",&start,&end);folyd();if(map[start][end]!=-1){printf("%d\n",map[start][end]);}else printf("-1\n");}return 0;}1.4.关键路径实现算法#include<iostream>#include<cstdio>#include<cstring>#define M 501using namespace std;int map[M][M],degree[M],dp[M];int ne;/*个数*/int topoplus(){int i,j,k,maxnum;for(i=0;i<ne;i++){j=1;while(j<=ne&°ree[j])j++;//直到一个度为零的顶点,这里不检查有多个度为零的情况//if(j>ne){break;}不是拓扑结构degree[j]=-1;for(k=1;k<=ne;k++){if(map[j][k]){if(map[j][k]+dp[j]>dp[k]){dp[k]=map[j][k]+dp[j];}degree[k]--;}}}for(i=0;i<=ne;i++){if(dp[i]>maxnum){maxnum=dp[i];}}return maxnum;}int main(){int a,b,v,i,j,nline;/*nline行*/while(scanf("%d%d",&ne,&nline)!=EOF){memset(map,0,sizeof(map));memset(degree,0,sizeof(degree));memset(dp,0,sizeof(dp));while(nline--){scanf("%d%d%d",&a,&b,&v);map[a][b]=v;/*a to b,v>0*/}for(i=1;i<=ne;i++){for(j=1;j<=ne;j++){if(map[i][j])degree[j]++;}}printf("%d\n",topoplus());/*拓扑改进*/}return 0;}1.5.二分图最大匹配的匈牙利算法#include<iostream>#include<cstdio>#define N 301using namespace std;int isuse[N]; //记录y中节点是否使用int lk[N]; //记录当前与y节点相连的x的节点int mat[N][N];//记录连接x和y的边,如果i和j之间有边则为1,否则为0 int gn,gm; //二分图中x和y中点的数目int can(int t){int i;for(i=1;i<=gm;i++){//下标从1开始if(isuse[i]==0 && mat[t][i]){isuse[i]=1;if(lk[i]==-1 || can(lk[i])){lk[i]=t;return 1;}}}return 0;}int MaxMatch(){int i,num=0;memset(lk,-1,sizeof(lk));for(i=1;i<=gn;i++){memset(isuse,0,sizeof(isuse));if(can(i))num++;}return num;}int main(){int t,i,j,k,tmp;scanf("%d",&t);while(t--){scanf("%d%d",&gn,&gm);memset(mat,0,sizeof(mat));//主要得到mat这个数组for(i=1;i<=gn;i++){scanf("%d",&k);for(j=1;j<=k;j++){scanf("%d",&tmp);mat[i][tmp]=1;//注意从1开始}}if(MaxMatch()==gn){printf("YES\n");}else printf("NO\n");}return 0;}/*In:23 33 1 2 32 1 21 13 32 1 32 1 31 1Out:YESNO*/1.6.并查集#include<iostream>#include<cstdio>using namespace std;const int N=1010;int pre[N];void Merge(int x,int y){int i,t,rx=x,ry=y;while(pre[rx]!=-1)//搜索x的树根rx=pre[rx];while(pre[ry]!=-1)//搜索y的树根ry=pre[ry];i=x;//压缩xwhile(pre[i]!=-1){t=pre[i];pre[i]=rx;i=t;}i=y;//压缩ywhile(pre[i]!=-1){t=pre[i];pre[i]=rx;i=t;}if(ry!=rx)//合并pre[ry]=rx;return;}int main(){int x,y,i,ans,n,m;while(scanf("%d",&n)&&n){scanf("%d",&m);memset(pre,-1,sizeof(pre));for(i=0;i<m;i++){//x与y连通scanf("%d %d",&x,&y);Merge(x,y);}ans=0;for(i=1;i<=n;i++)if(pre[i]==-1)ans++;printf("%d\n",ans-1);}}/*/showproblem.php?pid=1232 in:4 21 34 3999 0out:1998*/二、动规2.1.求最长子序列#include<iostream>#include<cstdio>#define M 1001using namespace std;char a[M],b[M];int dp[M+1][M+1],lena,lenb;void init(){int i,j;for(i=0;i<=lena;i++){for(j=0;j<=lenb;j++){dp[i][j]=0;}}}int cmax(int x,int y){return x>y?x:y;}int main(){int i,j,len;while(scanf("%s",a)!=EOF){scanf("%s",b);init();//下面这步很重要,否则会超时lena=strlen(a);lenb=strlen(b);for(i=0;i<lena;i++){for(j=0;j<lenb;j++){if(a[i]==b[j]){dp[i+1][j+1]=dp[i][j]+1;}else{dp[i+1][j+1]=cmax(dp[i][j+1],dp[i+1][j]);}}}//子序列长度printf("%d\n",dp[i][j]);/*打印出子序列*/len=1;for(i=1;i<=lena;i++){for(j=1;j<=lenb;j++){if(len==dp[i][j]){printf("%c",a[i-1]);len++;break;}}}printf("\n");}return 0;}2.2.求解最长升序列长度及子序列#include<iostream>#include<cstdio>#define M 1001using namespace std;int a[M],dp[M];void init(int n){int i;for(i=0;i<n;i++){dp[i]=1;}}int lis(int n){int i,j,maxlen=1;//初始长度为1for(i=n-2;i>=0;i--){for(j=n-1;j>i;j--){if(a[i]<a[j]){if(dp[j]+1>dp[i]){dp[i]=dp[j]+1;}if(dp[i]>maxlen)maxlen=dp[i];}}}return maxlen;}void showlis(int n,int maxlen){int i;for(i=0;i<n;i++){if(dp[i]==maxlen){printf("%d ",a[i]);maxlen--;}}printf("\n");}int main(){int t,n,i,maxlen;scanf("%d",&t);while(t--){/*1<=n<=1000*/scanf("%d",&n);for(i=0;i<n;i++){scanf("%d",&a[i]);}init(n);maxlen=lis(n);printf("%d\n",maxlen);//显示最长升序列showlis(n,maxlen);}return 0;}2.3.完全背包问题#include<iostream>#include<cstring>#include<cstdio>using namespace std;int type[]={150,200,350};//种类int dp[10001];int max(int a,int b){return a>b?a:b;}int main(){int t,n,i,j;scanf("%d",&t);while(t--){scanf("%d",&n);memset(dp,0,sizeof(dp));for(i=0;i<3;i++){for(j=type[i];j<=n;j++){//剩余容量为j时装的东西量最大dp[j]=max(dp[j],dp[j-type[i]]+type[i]);}}printf("%d\n",n-dp[n]);}return 0;}2.4.0-1背包问题#include<iostream>#include<cstdio>#include<cstring>#define M 1002using namespace std;int val[M],wei[M],dp[M][M];int cmax(int a,int b){return a>b?a:b;}int main(){int t,n,w,i,j;scanf("%d",&t);while(t--){scanf("%d%d",&n,&w);for(i=1;i<=n;i++){scanf("%d",&val[i]);}for(i=1;i<=n;i++){scanf("%d",&wei[i]);}memset(dp,0,sizeof(dp));for(i=1;i<=n;i++){for(j=0;j<=w;j++){if(j>=wei[i])dp[i][j]=cmax(dp[i-1][j-wei[i]]+val[i],dp[i-1][j]);else dp[i][j]=dp[i-1][j];}}printf("%d\n",dp[n][w]);}return 0;}2.5.母函数DP算法求组合数2.5.1.求母函数各系数值DP#include <iostream>#define M 17#define MAX 305using namespace std;int c1[MAX],c2[MAX],add[M+1];//add[]保存M种类void init(){int i;for(i=1;i<=M;i++){add[i]=i*i;}}int solve(int n){int i,j,k;//c1[k],c2[k]表示展开式中x^k的系数memset(c1,0,sizeof(c1));memset(c2,0,sizeof(c2));c1[0]=c2[0]=1;//使用前i种币时的情况,也即母函数展开前i个多项式的乘积 for(i=1;i<=M;i++){//求新的多项式中的系数for(j=0;j<n;j++){for(k=1;j+k*add[i]<=n;k++){c2[j+k*add[i]]+=c1[j];}}for(k=0;k<=n;k++){//滚动数组c1[k]=c2[k];}}return c1[n];}int main(){int n;init();while(scanf("%d",&n)&&n){printf("%d\n",solve(n));}return 0;}2.5.2.状态继承类DP求某个和是否存在#include<cstdio>#include<iostream>#include<cstring>using namespace std;bool dp[250002];int val[101],num[101];//对应的值和数量int main(){int n,i,j,sum,k;while(scanf("%d",&n)&&n>0){sum=0;for(i=0;i<n;i++){scanf("%d%d",&val[i],&num[i]);sum+=val[i]*num[i];}//dp中保存所有可能的组合memset(dp,0,sizeof(dp));dp[0]=1;//遍历n种物品for(i=0;i<n;i++){//对区间求for(j=sum/2;j>=0;j--){if(!dp[j]){for(k=1;k<=num[i]&&k*val[i]<=j;k++){dp[j]|=dp[j-k*val[i]];}}}}for(i=sum/2;i>=0;i--){if(dp[i]){printf("%d %d\n",sum-i,i);break;}}}return 0;}/*in:210 120 1320 230 1-1out:20 1040 40*/2.6.滚动数组求回文串问题#include<cstdio>#include<iostream>#include<cstring>#define M 5001using namespace std;char str[M],rstr[M];int dp[2][M];//滚动DPint cmax(int x,int y){return x>y?x:y;}int main(){int n,i,j,s1,s2;while(scanf("%d",&n)!=EOF){scanf(" %s",str);//反转字符数组for(i=0;i<n;i++){rstr[n-i-1]=str[i];}rstr[n]='\0';memset(dp,0,sizeof(dp));for(i=0;i<n;i++){for(j=0;j<n;j++){s1=i%2;s2=(i+1)%2;if(str[i]==rstr[j]){dp[s1][j+1]=dp[s2][j]+1;}else{dp[s1][j+1]=cmax(dp[s2][j+1],dp[s1][j]);}}}printf("%d\n",n-dp[(n-1)%2][n]);return 0;}/*/showproblem.php?pid=1513 in:5Ab3bdout:2*/三、贪心3.1.时间安排问题#include<iostream>#include<cstdio>#include<algorithm>#define M 101using namespace std;int n;struct Point{int s,e;}p[M];int cmp(Point a,Point b){if(a.s==b.s)return a.e<b.e;else return a.s<b.s;}int arrange(){int start,end,i,count=1;start=p[0].s;end=p[0].e;for(i=1;i<n;i++){if(p[i].s>=start&&p[i].e<=end){start=p[i].s;end=p[i].e;}else if(p[i].s>=end){count++;end=p[i].e;}}return count;}int main(){int i;while(scanf("%d",&n)&&n){for(i=0;i<n;i++){scanf("%d%d",&p[i].s,&p[i].e);}sort(p,p+n,cmp);printf("%d\n",arrange());}return 0;}3.2.求最大子段和#include<iostream>using namespace std;int main(){int t,n,i,a[100002];int beg,end,x,y,cursum,maxsum;cin>>t;while(t--){cin>>n;for(i=0;i<n;i++){cin>>a[i];}beg=end=1;cursum=maxsum=a[0];x=y=1;for(i=1;i<n;i++){if(a[i]+cursum<a[i]){cursum=a[i];x=i+1;}else{cursum+=a[i];}if(cursum>maxsum){maxsum=cursum;beg=x;end=i+1;}}cout<<maxsum<<" "<<beg<<" "<<end<<endl;}return 0;}/*in:25 6 -1 5 4 -77 0 6 -1 1 -6 7 -5out:14 1 47 1 6*/3.3.贪心求最少非递减序列数#include<iostream>#include<cstdio>#include<cstring>using namespace std;int a[1001];int main(){int n,i,j,len,count,high;while(scanf("%d",&n)!=EOF){for(i=0;i<n;i++){scanf("%d",&a[i]);}count=0;len=n;while(len){count++;high=30005;//最高值for(i=0;i<n;i++){if(a[i]&&a[i]<high){high=a[i];a[i]=0;//标记已用值len--;}}}printf("%d\n",count);}return 0;}/*in:8 389 207 155 300 299 170 158 65out:2*/四、数论4.1.简单求Cnk问题#include<iostream>using namespace std;int main(){int n,k,i;double sum;while(cin>>n>>k){if(n==0&&k==0)break;if(k>n-k)k=n-k;sum=1;for(i=1;i<=k;i++){sum*=(double)(n-k+i)/i*1.000000000001;//必需要乘 }cout<<(int)sum<<endl;}return 0;}4.2.巧求阶乘位数#include<iostream>#include<cmath>using namespace std;const double pi=acos(-1.0);//NOTES:piconst double e=2.71828182845904523536028747135266249775724709369995957; int main(){long long n,tt;cin>>tt;while (tt--){cin>>n;long long ans=(long long)((double)log10(sqrt(2*pi*n))+n*log10(n/e))+1;cout<<ans<<endl;}return 0;}4.3.线性算法求素数const int MAX=10000000;//求[2,MAX]间的素数bool isprime[MAX+1];int prime[MAX];//保存素数//返回素数表元素总数int getprime(){int i,j,pnum=0;//memset(isprime,0,sizeof(isprime));for(i=2;i<=MAX;i++){if(!isprime[i])prime[pnum++]=i;for(j=0;j<pnum&&prime[j]*i<=MAX;j++){isprime[prime[j]*i]=1;if(i%prime[j]==0)break;}}return pnum;}五、其他5.1.采用位操作递归求解示例#include<iostream>#include<cstdio>using namespace std;unsigned short in[50001],ste;/*用16位的ste保存16种状态*/ unsigned short power[]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768}; int n,m,maxnum,i,j;void dfs(int s,int count){if(count>maxnum)maxnum=count;for(i=s;i<m;i++){if(!(ste&in[i])){/*如果相与为0,说明材料未被使用*/ ste=ste|in[i];dfs(i+1,count+1);ste=ste&(~in[i]);}}}int main(){int tn,t;while(scanf("%d%d",&n,&m)!=EOF){if(n==0||m==0){printf("0\n");continue;}for(i=0;i<m;i++){scanf("%d",&tn);in[i]=0;for(j=1;j<=tn;j++){scanf("%d",&t);/*材料编号降为从0开始,防止益处*/in[i]=in[i]|power[t-1];}}ste=0;maxnum=0;dfs(0,0);printf("%d\n",maxnum);}return 0;}5.2.Stack和Queue用法#include<iostream>#include<stack>#include<queue>using namespace std;int main(){stack<int> s;queue<int> q;int a[]={1,2,3,4};/*加入*/for(int i=0;i<4;i++){s.push(a[i]);q.push(a[i]);}/*读取stack*/cout<<"stack-size:"<<s.size()<<endl;for(int i=0;i<4;i++){cout<<s.top()<<" ";s.pop();}cout<<endl<<"queue-size:"<<q.size()<<endl;/*读取queue*/cout<<"front:"<<q.front()<<"back:"<<q.back()<<endl;for(int i=0;i<4;i++){cout<<q.front()<<" ";q.pop();}cout<<endl;return 0;}5.3.map使用详解#include<iostream>#include<map>#include<string>#include<iterator>using namespace std;int main(){map<string,int>m;map<string,int>::iterator p;map<string,int>::reverse_iterator q;m["bd"]=2;m["ba"]=1;m["aa"]=3;m["bd"]=4;//按从小到大遍历for(p=m.begin();p!=m.end();p++){//注意不能使用p<m.end() cout<<p->first<<" "<<p->second<<endl;}//按从大到小遍历for(q=m.rbegin();q!=m.rend();q++){cout<<q->first<<" "<<q->second<<endl;}m.erase(m.begin());cout<<m.size()<<endl;//清楚全部m.clear();cout<<m.empty()<<endl;return 0;}5.4.字典树建立与查找#include<iostream>#include<cstring>#include<cstdio>#define M 26using namespace std;int ii;//只在Tree中使用struct Tree{Tree* next[M];int val;Tree(){for(ii=0;ii<M;ii++){next[ii]=0;}val=0;}~Tree(){for(ii=0;ii<M;ii++){delete(next[ii]);}}};int main(){char word[20];int len,i,j,count;Tree* root=new Tree;Tree* p;//建立字典树过程while(gets(word)){if(strcmp(word,"")==0)break;len=strlen(word);p=root;for(i=0;i<len;i++){j=word[i]-'a';if(p->next[j]==0){p->next[j]=new Tree;}p=p->next[j];(p->val)++;}word[0]='\0';}while(scanf("%s",word)!=EOF){len=strlen(word);p=root;for(i=0;i<len;i++){j=word[i]-'a';if(p->next[j]!=0){p=p->next[j];}else break;}if(i==len)printf("%d\n",p->val);else printf("0\n");}return 0;}/*In:bananabandbeeabsoluteacmbabbandabcout:231*/5.5.KMP匹配算法#include<iostream>#include<cstdio>#include<cstring>#define M 10001using namespace std;int s[M*100],t[M],next[M];//得到next数组,下标均从1开始void getnext(int m){int i=1,j=0;next[1]=0;while(i<=m){if(j==0||t[i]==t[j]){++i;++j;next[i]=j;}else j=next[j];}}//找不到则返回-1int kmp(int n,int m){int i=0,j=1;getnext(m);while(i<=n&&j<=m){if(!j||s[i]==t[j]){++i;++j;}elsej=next[j];}if(j>m)return i-m;else return -1;}int main(){int test,m,n,i;scanf("%d",&test);while(test--){scanf("%d %d",&n,&m);//主串s,长度为nfor(i=1;i<=n;i++)scanf("%d",&s[i]);//横式串t,长度为mfor(i=1;i<=m;i++)scanf("%d",&t[i]);printf("%d\n",kmp(n,m));}return 0;}5.6.后缀数组求最长连续公共子序列长度#include<iostream>#include<cstdio>#include<algorithm>#define M 100001using namespace std;char message[M*2];/*后缀数组*/int height[M*2];int _array[2][M*2];int _rank[2][M*2];int cnt[M*2];int *array, *rank, *narray, *nrank;/*得到最长连续公共子序列长度*/int suffix(int len1,int len2,int len){int i,k;memset(cnt,0,1024);for(i=0;i<len;++i){++cnt[message[i]];}for(i=1;i<= 'z';++i){cnt[i]+=cnt[i-1];}array = _array[0];rank = _rank[0];for(i=len-1;i>=0;--i){array[--cnt[message[i]]]=i;}rank[array[0]] = 0;for(i=1;i<len;i++){rank[array[i]]=rank[array[i-1]];if(message[array[i]]!=message[array[i-1]]){ rank[array[i]]++;}}narray = _array[1];nrank = _rank[1];for(k=1;k<len&&rank[array[len-1]]<len-1;k<<=1){for(i=0;i<len;++i){cnt[rank[array[i]]]=i+1;}for(i=len-1;i>=0;--i){if(array[i] >= k){// array[i]是当前的最大值,所以array[i] - k//是其相同前缀中(rank相同)的最大值narray[--cnt[rank[array[i]-k]]]=array[i]-k;}}for(i=len-k;i<len;++i){//这些没有k后缀,所以他们是最后面的k个,他的位置已经比较出来narray[--cnt[rank[i]]]=i;}nrank[narray[0]] = 0;for (i=1;i<len;++i){nrank[narray[i]]=nrank[narray[i-1]];if(rank[narray[i]]!= rank[narray[i-1]] ||rank[narray[i]+k]!=rank[narray[i-1]+k]){//如果前缀的排名不同,则++;如果前缀相同,但是后缀不同,也++ nrank[narray[i]]++;}}swap(nrank, rank);swap(narray, array);}int ret=0,hei;for(i=1;i<len;++i){if(((array[i]<len1&&array[i-1]>=len1) ||(array[i]>=len1&&array[i-1]<len1))){hei = 0;while(message[array[i]+ hei]==message[array[i-1]+hei]){hei++;}ret = max(ret, hei);}}return ret;}int main(){int len,len1,len2;while(gets(message)!=NULL){len1 = strlen(message);gets(message + len1);len2 = strlen(message+len1);len = len1 + len2;printf("%d\n",suffix(len1,len2,len));}return 0;}5.7.循环字符串最小位置表示及同构判断#include<cstdio>#include<iostream>#include<cstring>#include<string>using namespace std;//返回两个字符串是否同构//len为s1或S2的长度,s1与s2等长//pos1与pos2为字符循环最小表示位置,从0开始bool CircularMatch(string s1, string s2, int len, int& pos1, int& pos2) {int p1 = 0, p2 = 0, k, t1, t2;pos1 = pos2 = -1;while (1) {k = 0;while (1) {t1 = (p1+k)%len; t2 = (p2+k)%len;if(s1[t1] > s2[t2]) {p1 = p1+k+1;if (p1 >= len) return false;break;}else if (s1[t1] < s2[t2]) {p2 = p2+k+1;if (p2 >= len) return false;break;}else k++;if (k == len) {pos1 = p1; pos2 = p2;return true;}}}}//返回字符串循环最小表示的位置,从0开始int MinCircularDenote(string s, int len) {int p1 = 0, p2 = 1, k, t1, t2;while (1) {k = 0;while (1) {t1 = (p1+k)%len; t2 = (p2+k)%len;if(s[t1] > s[t2]) {if (p1+k+1 <= p2) p1 = p2+1;else p1 = p1+k+1;if (p1 >= len) return p2;break;}else if (s[t1] < s[t2]) {if (p2+k+1 <= p1) p2 = p1+1;else p2 = p2+k+1;if (p2 >= len) return p1;break;}else k++;if (k == len)return (p1<p2 ? p1 : p2);}}}//返回字符串循环最大表示的位置,从0开始int MaxCircularDenote(string str,int len) {int p1 = 0, p2 = 1, k, t1, t2;while (1) {k = 0;while (1) {t1 = (p1+k)%len; t2 = (p2+k)%len;if(str[t1] < str[t2]) {if (p1+k+1 <= p2) p1 = p2+1; else p1 = p1+k+1;if (p1 >= len) return p2;break;}else if (str[t1] > str[t2]) {if (p2+k+1 <= p1) p2 = p1+1;else p2 = p2+k+1;if (p2 >= len) return p1;break;}else k++;if (k == len)return (p1<p2 ? p1 : p2);}}}int main(){string s1,s2;int pos1,pos2,len;while(cin>>s1>>s2){len=s1.length();cout<<MinCircularDenote(s1,len)<<endl;cout<<MaxCircularDenote(s1,len)<<endl;s1+=s1;//字符串加倍s2+=s2;cout<<CircularMatch(s1,s2,len, pos1,pos2)<<endl;cout<<pos1<<endl<<pos2<<endl;}return 0;}5.8.求哈夫曼树编码长度#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#define M 27using namespace std;char line[100001];int tree[M],tmp[M];//保存权值int cmp(int a,int b){return a>b;}//对序号为index统计长度int huffman(int n,int index){if(n==1)return 1;//一个点时返回1int i,j,count,max,len,t;for(i=0;i<n;i++){tmp[i]=tree[i];}count=max=n-1;len=0;while(count--){if(index==max||index==max-1){len++;index=max-1;}tmp[max-1]+=tmp[max];j=--max;while(j>0&&tmp[j]>tmp[j-1]){t=tmp[j];tmp[j]=tmp[j-1];tmp[j-1]=t;if(index==j){index--;}else if(index==j-1){index++;}j--;}}return len;}int main(){int i,j,len,sum,n;int ch[M];while(gets(line)!=NULL){if(strcmp(line,"END")==0)break;len=strlen(line);memset(ch,0,sizeof(ch));for(i=0;i<len;i++){if(line[i]=='_'){ch[0]++;}else ch[line[i]-'A'+1]++;}//权值压缩到tree[]数组中for(j=0,i=0;i<M;i++){if(ch[i]){tree[j++]=ch[i];}}n=j;sort(tree,tree+n,cmp);for(sum=0,i=0;i<n;i++){sum+=tree[i]*huffman(n,i);}printf("%d %d %.1lf\n",len*8,sum,len*8.0/(sum*1.0));}return 0;}/*/showproblem.php?pid=1053in:AAAAABCDTHE_CAT_IN_THE_HATENDout:64 13 4.9144 51 2.8*/5.9.堆排序算法#include<cstdio>#include<cstdlib>using namespace std;void adjust(int a[],int s,int len){int t,i;t=a[s];for(i=s*2;i<len;i*=2){if(i<(len-1)&&a[i]<a[i+1])i++;if(t>=a[i])break;a[s]=a[i];s=i;}a[s]=t;}void sort(int a[],int len){int i,t;for(i=(len-1)/2;i>=0;i--){adjust(a,i,len);}for(i=len-1;i>1;i--){a[i]=a[0];a[0]=t;adjust(a,0,i-1);}if(a[0]>a[1]){t=a[0];a[0]=a[1];a[1]=t;}}int main(){int a[1000],i,n;scanf("%d",&n);//for(i=0;i<n;i++)// scanf("%d",a+i);for(i=0;i<n;i++)a[i]=rand()%10000;sort(a,n);for(i=0;i<n;i++)printf("%d ",a[i]);printf("\n");return 0;}//2 38 4 99 10 2 22 1 -43 22 33 91 78 335.10.线段树着色问题#include <iostream>#define N 8003#define NoCol -1#define MulCol -2using namespace std;struct SegTree{int l,r,c;}st[N*4];//一般大小开成节点数的4倍,不需要担心空间问题int seg[N],col[N];int n,sat,end;//创建线段树void segTreeCre(int l,int r,int i=1){int mid;st[i].l=l;。
ACM数论相关模板
求最大公约数(欧几里得算法)int gcd(int a, int b){if (b == 0) return a;return gcd(b, a % b);}求最小公倍数Lcm(a, b) = a * b / gcd(a, b);判断是否为素数#include <iostream>#include <stdio.h>#include <math.h>using namespace std;bool judgeprime(int n){bool flag =true;int m = sqrt(n);for (int i = 2; i <= m; i++){if (n % i == 0){flag = false;break;}}if (flag) printf("yes\n");else printf("no\n");}快速幂求%yx pLong long pw(long long x, long long y,long long p){if (y == 0) return 1LL;long long tmp = pw (x, y / 2, p);if (y & 1) return tmp * tmp % p * x % p;return tmp * tmp % p;}埃拉托斯特尼筛法寻找n 以内的素数 void findprime(int n){bool isprime[10005];int prime[10005], i, j, total;memset(isprime, true, sizeof(isprime));total=0;for (i = 2; i<=n; i++){if (isprime[i]){prime[total++] = i;for (j=i*i;j<=n;j+=i)isprime[j]=false;}}for (i = 0; i < total; i++)printf("%d ",prime[i]);}欧拉筛法void makePrime(){memset(isPrime,true,sizeof(isPrime));for(int i=2; i<=MAXN; i++){if(isPrime[i]) prime[total++]=i;for(int j=0; j<total && i*prime[j]<=MAX; j++){isPrime[i*prime[j]]=false;//i此时不是素数,只是拓展用if(i%prime[j]==0) break;}}}。
ACM算法--枚举方法(指数枚举,组合枚举)模板
ACM算法--枚举⽅法(指数枚举,组合枚举)模板// 递归实现指数型枚举vector<int> chosen;void calc(int x) {if (x == n + 1) {for (int i = 0; i < chosen.size(); i++)printf("%d ", chosen[i]);puts("");return;}calc(x + 1);chosen.push_back(x);calc(x + 1);chosen.pop_back();}// 递归实现组合型枚举vector<int> chosen;void calc(int x) {if (chosen.size() > m || chosen.size() + (n - x + 1) < m) return;if (x == n + 1) {for (int i = 0; i < chosen.size(); i++)printf("%d ", chosen[i]);puts("");return;}calc(x + 1);chosen.push_back(x);calc(x + 1);chosen.pop_back();}// 递归实现排列型枚举int order[20];bool chosen[20];void calc(int k) {if (k == n + 1) {for (int i = 1; i <= n; i++)printf("%d ", order[i]);puts("");return;}for (int i = 1; i <= n; i++) {if (chosen[i]) continue;order[k] = i;chosen[i] = 1;calc(k + 1);chosen[i] = 0;order[k] = 0;}}// 模拟机器实现,把组合型枚举改为⾮递归vector<int> chosen;int stack[100010], top = 0, address = 0;void call(int x, int ret_addr) { // 模拟计算机汇编指令callint old_top = top;stack[++top] = x; // 参数xstack[++top] = ret_addr; // 返回地址标号stack[++top] = old_top; // 在栈顶记录以前的top值}int ret() { // 模拟计算机汇编指令retint ret_addr = stack[top - 1];top = stack[top]; // 恢复以前的top值return ret_addr;}int main() {int n, m;cin >> n >> m;call(1, 0); // calc(1)while (top) {int x = stack[top - 2]; // 获取参数switch (address) {case 0:if (chosen.size() > m || chosen.size() + (n - x + 1) < m) {address = ret(); // returncontinue;}if (x == n + 1) {for (int i = 0; i < chosen.size(); i++)printf("%d ", chosen[i]);puts("");address = ret(); // returncontinue;}call(x + 1, 1); // 相当于calc(x + 1),返回后会从case 1继续执⾏ address = 0;continue; // 回到while循环开头,相当于开始新的递归case 1:chosen.push_back(x);call(x + 1, 2); // 相当于calc(x + 1),返回后会从case 2继续执⾏ address = 0;continue; // 回到while循环开头,相当于开始新的递归case 2:chosen.pop_back();address = ret(); // 相当于原calc函数结尾,执⾏return}}}。
ACM常用算法模板
专用模板目录:一、图论1.最大团2.拓扑排序3.最短路和次短路4.SAP模板5.已知各点度,问能否组成一个简单图6.KRUSKAL7. Prim算法求最小生成树8. Dijkstra9 . Bellman-ford10. SPFA11. Kosaraju 模板12. tarjan 模板二、数学1. 剩余定理2. N!中质因子P的个数3.拓展欧几里得4.三角形的各中心到顶点的距离和5.三角形外接圆半径周长6.归并排序求逆序数7. 求N!的位数8.欧拉函数9. Miller-Rabin,大整数分解,求欧拉函数10. 第一类斯特林数11.计算表达式12.约瑟夫问题13.高斯消元法14. Baby-step,giant-step n是素数.n任意15. a^b%c=a ^(b%eular(c)+eular(c)) % c16.判断第二类斯特林数的奇偶性17.求组合数C(n,r)18.进制转换19.Ronberg算法计算积分20.行列式计算21. 返回x 的二进制表示中从低到高的第i位22.高精度运算 +-*/23.超级素数筛选三、数据结构1.树状数组2.线段树求区间的最大、小值3.线段树求区间和4.单调队列5.KMP模板6. 划分树,求区间第k小数7.最大堆,最小堆模板8. RMQ模板求区间最大、最小值9.快速排序,归并排序求逆序数.10.拓展KMP四、计算几何1.凸包面积2.Pick公式求三角形内部有多少点3.多边形边上内部各多少点以及面积pick4.平面最远点对5.判断矩形是否在矩形内6.判断点是否在多边形内7.判断4个点(三维)是否共面8.凸包周长9.等周定理变形一直两端点和周长求最大面积10.平面最近点对11.单位圆最多覆盖多少点(包括边上)12.多边形费马点求点到多边形各个点的最短距离13.矩形并周长14.zoj 2500 求两球体积并一、图论1.最大团#include<iostream>#include<algorithm>using namespace std;int n,m;int cn;//当前顶点数int best;//当前最大顶点数int vis[50];//当前解int bestn[50];//最优解int map[50][50];//临界表void dfs(int i){if(i>n){for(int j=1;j<=n;j++) bestn[j]=vis[j];best=cn;return ;}int ok=1;for(int j=1;j<i;j++){if(vis[j]==1&&map[i][j]==0){ok=0;break;}}if(ok){//进入左子树vis[i]=1;cn++;dfs(i+1);cn--;}if(cn+n-i>best){//进入右子树vis[i]=0;dfs(i+1);}}int main(){while(scanf("%d%d",&n,&m)==2){memset(vis,0,sizeof(vis));memset(map,0,sizeof(map));while(m--){int p,q;scanf("%d%d",&p,&q);map[p][q]=map[q][p]=1;//无向图}cn=0;best=0;dfs(1);printf("%d\n",best);}return 0;}2.拓扑排序#include<iostream>#include<cstring>using namespace std;int map[105][105],in[105],vis[105],ans[105],n;int flag;void dfs(int step){if(flag) return ;if(step==n+1) {flag=1; printf("%d",ans[1]);for(int i=2;i<=n;i++) printf(" %d",ans[i]);printf("\n");return ;}for(int i=1;i<=n;i++){if(vis[i]==0&&in[i]==0){vis[i]=1;for(int j=1;j<=n;j++){if(map[i][j]>0){map[i][j]=-map[i][j];in[j]--;}}ans[step]=i;dfs(step+1);vis[i]=0;for(int j=1;j<=n;j++){if(map[i][j]<0){map[i][j]=-map[i][j];in[j]++;}}}}}int main(){while(scanf("%d",&n)==1){flag=0;memset(map,0,sizeof(map));memset(vis,0,sizeof(vis));memset(in,0,sizeof(in));for(int i=1;i<=n;i++){int t;while(scanf("%d",&t),t){map[i][t]=1;in[t]++;}}dfs(1);}return 0;}3.最短路和次短路#include<iostream>#include<cstdio>#include<vector>#include<cstring>using namespace std;class Node{public:int e,w;//表示终点和边权};const int inf=(1<<25);int main(){int ci;cin>>ci;while(ci--){vector<Node> G[1005];//用邻接表存边int n,m;cin>>n>>m;for(int i=1;i<=m;i++){Node q;int u;cin>>u>>q.e>>q.w;G[u].push_back(q);}int s,f;//起点和终点cin>>s>>f;//dijkstra 求最短路和次短路int flag[1005][2];int dis[1005][2],cnt[1005][2];//0表示最短路,1表示次短路memset(flag,0,sizeof(flag));for(int i=1;i<=n;i++) dis[i][0]=dis[i][1]=inf;dis[s][0]=0;cnt[s][0]=1;//初始化for(int c=0;c<2*n;c++) //找最短路和次短路,故要进行2*n次循环也可以改成while(1){int temp=inf,u=-1,k;//找s-S'集合中的最短路径,u记录点的序号,k记录是最短路或者是次短路for(int j=1;j<=n;j++){if(flag[j][0]==0&&temp>dis[j][0]) temp=dis[j][0],u=j,k=0;else if(flag[j][1]==0&&temp>dis[j][1]) temp=dis[j][1],u=j,k=1;}if(temp==inf) break;//S'集合为空或者不联通,算法结束//更新路径flag[u][k]=1;for(int l=0;l<G[u].size();l++){int d=dis[u][k]+G[u][l].w,j=G[u][l].e;//important//4种情况if(d<dis[j][0]){dis[j][1]=dis[j][0];cnt[j][1]=cnt[j][0];dis[j][0]=d;cnt[j][0]=cnt[u][k];}else if(d==dis[j][0]){cnt[j][0]+=cnt[u][k];}else if(d<dis[j][1]){dis[j][1]=d;cnt[j][1]=cnt[u][k];}else if(d==dis[j][1]){cnt[j][1]+=cnt[u][k];}}}int num=cnt[f][0];//最短路int cc=cnt[f][1];//次短路}return 0;}4.SAP模板#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int inf=(1<<31)-1;const int point_num=300;int cap[point_num][point_num],dist[point_num],gap[point_num];//初始化见main里面int s0,t0,n;//源,汇和点数int find_path(int p,int limit=0x3f3f3f3f){if(p==t0) return limit;for(int i=0;i<n;i++)if(dist[p]==dist[i]+1 && cap[p][i]>0){int t=find_path(i,min(cap[p][i],limit));if(t<0) return t;if(t>0){cap[p][i]-=t;cap[i][p]+=t;return t;}}int label=n;for(int i=0;i<n;i++) if(cap[p][i]>0) label=min(label,dist[i]+1);if(--gap[dist[p]]==0 || dist[s0]>=n ) return -1;++gap[dist[p]=label];return 0;}int sap(){//初始化s,ts0=0,t0=n-1;int t=0,maxflow=0;gap[0]=n;while((t=find_path(s0))>=0) maxflow+=t;return maxflow;}int main(){int ci;while(cin>>ci>>n){//初始化memset(cap,0,sizeof(cap));memset(dist,0,sizeof(dist));memset(gap,0,sizeof(gap));//初始化capwhile(ci--){int x,y,c;cin>>x>>y>>c;x--;y--;cap[x][y]+=c;//因题而异}int ans=sap();cout<<ans<<endl;}return 0;}5.已知各点度,问能否组成一个简单图#include<iostream>#include<cstdio>#include<algorithm>using namespace std;const int inf=(1<<30);int d[1100];bool cmp(int x,int y){return x>y;}int main(){int ci;scanf("%d",&ci);while(ci--){int n,flag=1,cnt=0;scanf("%d",&n); for(int i=0;i<n;i++){scanf("%d",&d[i]);if(d[i]>n-1||d[i]<=0) flag=0; cnt+=d[i];}if(flag==0||cnt%2){printf("no\n");continue;}sort(d,d+n,cmp);for(int l=n;l>0;l--){for(int i=1;i<l&&d[0];i++){d[0]--,d[i]--;if(d[i]<0){flag=0;break;}}if(d[0]) flag=0;if(flag==0) break;d[0]=-inf;sort(d,d+l,cmp);}if(flag) printf("yes\n");else printf("no\n");}return 0;}6.KRUSKAL#include<iostream>#include<algorithm>using namespace std;int u[15005],v[15005],w[15005],fath[15005],r[15005];int ans1[15005],ans2[15005];bool cmp(int i,int j){return w[i]<w[j];}int find(int x){return fath[x]==x?x:fath[x]=find(fath[x]);}int main(){int n,m;cin>>n>>m;for(int i=1;i<=n;i++) fath[i]=i;for(int i=1;i<=m;i++) r[i]=i;for(int i=1;i<=m;i++){cin>>u[i]>>v[i]>>w[i];}sort(r+1,r+m+1,cmp);int maxn=0,ans=0,k=0;for(int i=1;i<=m;i++){int e=r[i];int x=find(u[e]),y=find(v[e]);if(x!=y){ans+=w[e];fath[x]=y;if(w[e]>maxn) maxn=w[e];ans1[k]=u[e];ans2[k++]=v[e];}}return 0;}7.prime求最小生成树语法:prim(Graph G,int vcount,int father[]);参数:G:图,用邻接矩阵表示vcount:表示图的顶点个数father[]:用来记录每个节点的父节点返回值:null注意:常数max_vertexes 为图最大节点数常数infinity为无穷大源程序:#define infinity 1000000#define max_vertexes 5typedef int Graph[max_vertexes][max_vertexes];void prim(Graph G,int vcount,int father[]){int i,j,k;intlowcost[max_vertexes],closeset[max_vertexes],used[max_vertexes]; for (i=0;i<vcount;i++){lowcost[i]=G[0][i];closeset[i]=0;used[i]=0;father[i]=-1;}used[0]=1;for (i=1;i<vcount;i++){j=0;while (used[j]) j++;for (k=0;k<vcount;k++)if ((!used[k])&&(lowcost[k]<lowcost[j])) j=k;father[j]=closeset[j];used[j]=1;for (k=0;k<vcount;k++)if (!used[k]&&(G[j][k]<lowcost[k])){ lowcost[k]=G[j][k];closeset[k]=j; }}}8.Dijkstra语法:result=Dijkstra(Graph G,int n,int s,int t, int path[]); 参数:G:图,用邻接矩阵表示n:图的顶点个数s:开始节点t:目标节点path[]:用于返回由开始节点到目标节点的路径返回值:最短路径长度注意:输入的图的权必须非负顶点标号从0 开始用如下方法打印路径:i=t;while (i!=s){printf("%d<--",i+1);i=path[i];}printf("%d\n",s+1);源程序:int Dijkstra(Graph G,int n,int s,int t, int path[]){int i,j,w,minc,d[max_vertexes],mark[max_vertexes];for (i=0;i<n;i++) mark[i]=0;for (i=0;i<n;i++){ d[i]=G[s][i];path[i]=s; }mark[s]=1;path[s]=0;d[s]=0;for (i=1;i<n;i++){minc=infinity;w=0;for (j=0;j<n;j++)if ((mark[j]==0)&&(minc>=d[j])) {minc=d[j];w=j;}mark[w]=1;for (j=0;j<n;j++)if((mark[j]==0)&&(G[w][j]!=infinity)&&(d[j]>d[w]+G[w][j])){ d[j]=d[w]+G[w][j];path[j]=w; }}return d[t];}9.Bellman-ford语法:result=Bellman_ford(Graph G,int n,int s,int t,int path[],int success);参数:G:图,用邻接矩阵表示n:图的顶点个数s:开始节点t:目标节点path[]:用于返回由开始节点到目标节点的路径success:函数是否执行成功返回值:最短路径长度注意:输入的图的权可以为负,如果存在一个从源点可达的权为负的回路则success=0顶点标号从0 开始用如下方法打印路径:i=t;while (i!=s){printf("%d<--",i+1);i=path[i];}printf("%d\n",s+1);源程序:int Bellman_ford(Graph G,int n,int s,int t,int path[],int success){int i,j,k,d[max_vertexes];for (i=0;i<n;i++) {d[i]=infinity;path[i]=0;}d[s]=0;for (k=1;k<n;k++)for (i=0;i<n;i++)for (j=0;j<n;j++)if (d[j]>d[i]+G[i][j]){d[j]=d[i]+G[i][j];path[j]=i;}success=0;for (i=0;i<n;i++)for (j=0;j<n;j++)if (d[j]>d[i]+G[i][j]) return 0;success=1;return d[t];}10. SPFA#include<iostream>#include<cstdio>#include<cstring>#include<vector>using namespace std;const __int64 maxn=1001000;const __int64 inf=1000100000;struct edge//邻接表{__int64 t,w;//s->t=w;__int64 next;//数组模拟指针};__int64 p[maxn],pf[maxn];//邻接表头节点edge G[maxn],Gf[maxn];//邻接表__int64 V,E;//点数[1-n] 边数__int64 dis[maxn];__int64 que[maxn],fro,rear;//模拟队列__int64 vis[maxn];__int64 inque[maxn];//入队次数bool spfa(__int64 s0){fro=rear=0;for(__int64 i=1;i<=V;i++) dis[i]=inf;dis[s0]=0;memset(vis,0,sizeof(vis));memset(inque,0,sizeof(inque));que[rear++]=s0;vis[s0]=1;inque[s0]++;while(fro!=rear){__int64 u=que[fro];fro++;if(fro==maxn) fro=0;vis[u]=0;for(__int64 i=p[u];i!=-1;i=G[i].next){__int64 s=u,t=G[i].t,w=G[i].w;if(dis[t]>dis[s]+w){dis[t]=dis[s]+w;if(vis[t]==0){que[rear++]=t,vis[t]=1;inque[t]++;if(inque[t]>V) return false;if(rear==maxn) rear=0;}}}}return true;}int main(){__int64 ci;scanf("%I64d",&ci);while(ci--){scanf("%I64d%I64d",&V,&E);memset(p,-1,sizeof(p));memset(pf,-1,sizeof(pf)); for(__int64 i=0;i<E;i++){__int64 u,v,w;scanf("%I64d%I64d%I64d",&u,&v,&w);G[i].t=v;G[i].w=w;G[i].next=p[u];p[u]=i;Gf[i].t=u;Gf[i].w=w;Gf[i].next=pf[v];pf[v]=i;}__int64 ans=0;spfa(1);//求第一个点到其他点的最短距离和for(__int64 i=1;i<=V;i++) ans+=dis[i];//反方向再来一次spfa 求其他点到第一个点的最短距离和 for(__int64 i=1;i<=V;i++) p[i]=pf[i];for(__int64 i=0;i<E;i++) G[i]=Gf[i];spfa(1);for(__int64 i=1;i<=V;i++) ans+=dis[i];printf("%I64d\n",ans);}return 0;}11.Kosaraju模板#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=100000;struct edge{int t,w;//u->t=w;int next;};int V,E;//点数(从1开始),边数int p[maxn],pf[maxn];//邻接表原图,逆图edge G[maxn],Gf[maxn];//邻接表原图,逆图int l,lf;void init(){memset(p,-1,sizeof(p));memset(pf,-1,sizeof(pf));l=lf=0;}void addedge(int u,int t,int w,int l){G[l].w=w;G[l].t=t;G[l].next=p[u];p[u]=l;}void addedgef(int u,int t,int w,int lf){Gf[l].w=w;Gf[l].t=t;Gf[l].next=pf[u];pf[u]=l;}///Kosaraju算法,返回为强连通分量个数bool flag[maxn]; //访问标志数组int belg[maxn]; //存储强连通分量,其中belg[i]表示顶点i属于第belg[i]个强连通分量int numb[maxn]; //结束时间(出栈顺序)标记,其中numb[i]表示离开时间为i的顶点//用于第一次深搜,求得numb[1..n]的值void VisitOne(int cur, int &sig){flag[cur] = true;for (int i=p[cur];i!=-1;i=G[i].next){if (!flag[G[i].t]){VisitOne(G[i].t,sig);}}numb[++sig] = cur;}//用于第二次深搜,求得belg[1..n]的值void VisitTwo(int cur, int sig){flag[cur] = true;belg[cur] = sig;for (int i=pf[cur];i!=-1;i=Gf[i].next){if (!flag[Gf[i].t]){VisitTwo(Gf[i].t,sig);}}//Kosaraju算法,返回为强连通分量个数int Kosaraju_StronglyConnectedComponent(){int i, sig;//第一次深搜memset(flag,0,sizeof(flag));for ( sig=0,i=1; i<=V; ++i ){if ( false==flag[i] ){VisitOne(i,sig);}}//第二次深搜memset(flag,0,sizeof(flag));for ( sig=0,i=V; i>0; --i ){if ( false==flag[numb[i]] ){VisitTwo(numb[i],++sig);}}return sig;}int main(){while(scanf("%d",&V)==1){init();for(int i=1;i<=V;i++){int u=i,t,w=1;while(scanf("%d",&t)==1&&t){E++;addedge(u,t,w,l++);addedgef(t,u,w,lf++);}}int ans=Kosaraju_StronglyConnectedComponent(); printf("%d\n",ans);}return 0;12.tarjan模板//自己模板#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=100000;int V,E;//点数(1) 边数struct edge//邻接表{int t,w;//u->t=w;int next;};int p[maxn];//表头节点edge G[maxn];int l;void init(){memset(p,-1,sizeof(p));l=0;}//添加边void addedge(int u,int t,int w,int l)//u->t=w;{G[l].w=w;G[l].t=t;G[l].next=p[u];p[u]=l;}//tarjan算法求有向图强联通分量int dfn[maxn],lowc[maxn];//dfn[u]节点u搜索的次序编号,lowc[u]u或者u的子树能够追溯到的栈中的最早的节点int belg[maxn];//第i个节点属于belg[i]个强连通分量int stck[maxn],stop;//stck栈int instck[maxn];//第i个节点是否在栈中int scnt;//强联通分量int index;void dfs(int i){dfn[i]=lowc[i]=++index;instck[i]=1;//节点i入栈stck[++stop]=i;for(int j=p[i];j!=-1;j=G[j].next){int t=G[j].t;//更新lowc数组if(!dfn[t])//t没有遍历过{dfs(t);if(lowc[i]>lowc[t]) lowc[i]=lowc[t];}//t是i的祖先节点else if(instck[t]&&lowc[i]>dfn[t]) lowc[i]=dfn[t];}//是强连通分量的根节点if(dfn[i]==lowc[i]){scnt++;int t;do{t=stck[stop--];instck[t]=0;belg[t]=scnt;}while(t!=i);}}int tarjan(){stop=scnt=index=0;memset(dfn,0,sizeof(dfn));memset(instck,0,sizeof(instck));for(int i=1;i<=V;i++){if(!dfn[i]) dfs(i);}return scnt;}int main(){while(scanf("%d",&V)==1){init();for(int i=1;i<=V;i++){int x;while(scanf("%d",&x)==1&&x){E++;addedge(i,x,1,l++);}}int ans=tarjan();printf("%d\n",ans);}return 0;}//吉大模板邻接表版#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=100000;int V,E;//点数(1) 边数struct edge//邻接表{int t,w;//u->t=w;int next;};int p[maxn];//表头节点edge G[maxn];int l;void init(){memset(p,-1,sizeof(p));l=0;}//添加边void addedge(int u,int t,int w,int l)//u->t=w;{G[l].w=w;G[l].t=t;G[l].next=p[u];p[u]=l;}//tarjan算法求有向图强联通分量int dfn[maxn],lowc[maxn];//dfn[u]节点u搜索的次序编号,lowc[u]u或者u的子树能够追溯到的栈中的最早的节点int stck[maxn],stop;//stck栈int pre[maxn];//int scnt;//强联通分量int cnt;//void dfs(int v)//1-V{int t,minc=lowc[v]=pre[v]=cnt++;stck[stop++]=v;for(int i=p[v];i!=-1;i=G[i].next){int pv=G[i].t;if(pre[pv]==-1) dfs(pv);if(lowc[pv]<minc) minc=lowc[pv]; }if(minc<lowc[v]){lowc[v]=minc;return ;}do{dfn[t=stck[--stop]]=scnt;lowc[t]=V;}while(t!=v);++scnt;}int tarjan(){stop=cnt=scnt=0;memset(pre,-1,sizeof(pre));for(int i=1;i<=V;i++){if(pre[i]==-1) dfs(i);}return scnt;}int main(){while(scanf("%d",&V)==1){init();for(int i=1;i<=V;i++){int x;while(scanf("%d",&x)==1&&x){E++;addedge(i,x,1,l++);}}int ans=tarjan();printf("%d\n",ans);}return 0;}二、数学1.剩余定理int mod(int c[],int b[],int n){int all_multy=1,sum=0;int i,j,x[5];for(i=0;i<n;i++)all_multy*=c[i];for(i=0;i<n;i++)x[i]=all_multy/c[i];for(i=0;i<n;i++){j=1;while((x[i]*j)%c[i]!=1)j++;x[i]*=j;}for(i=0;i<n;i++)sum+=(b[i]*x[i]);return sum%all_multy;}2.N!中质因子P的个数//对于任意质数p,n!中有(n/p+n/p^2+n/p^3+...)个质因子p。
核心算法——ACM模板
核心算法——ACM模板一、贪心算法 (2)1、区间选点 (2)2、区间覆盖 (2)3、不相交区间 (2)4、哈夫曼编码 (2)5、最小值最大化、最大值最小化(二分查找) (2)二、动态规划 (5)1、最长公共子序列(LCS) (5)2、最长上升公共子序列(LIS) (7)3、子段和 (9)4、DAG上的动态规划 (13)5、区间DP (17)6、状态压缩DP (24)7、双线DP (30)8、背包问题(见背包九讲) (32)三、数据结构 (32)1、并查集 (32)2、树状数组 (34)3、(字符串)KMP匹配 (37)四、最小生成树算法 (41)Prime核心算法 (41)Kruskal算法 (44)五、单源最短路径 (50)Dijkstra核心算法 (50)Bellman_Ford算法 (54)SPFA算法(Bellman_Ford的队列实现) (58)六、二分图匹配 (61)1、匈牙利算法 (61)七、网络流 (63)1、SAP算法 (64)2、Dinic算法 (68)一、贪心算法1、区间问题区间选点选取尽量少的点覆盖所有的区间,是每个区间至少包含一个点。
对区间右端点进行排序。
区间覆盖选取尽量少的区间覆盖整个区域。
对左端点进行排序。
不相交区间选取尽量多的不相交区间。
对区间右端点进行排序。
2、哈夫曼编码3、最小值最大化、最大值最小化(二分查找)NYOJ 疯牛问题(最小值最大化)农夫John 建造了一座很长的畜栏,它包括N (2 <= N <= 100,000)个隔间,这些小隔间依次编号为x1,...,xN (0 <= xi <= 1,000,000,000).但是,John的C (2 <= C <= N)头牛们并不喜欢这种布局,而且几头牛放在一个隔间里,他们就要发生争斗。
为了不让牛互相伤害。
John决定自己给牛分配隔间,使任意两头牛之间的最小距离尽可能的大,那么,这个最大的最小距离是什么呢?#include#include#includeusing namespace std;int n, c;int pos[100005];bool judge(int k){int cnt = 1;int st = pos[0];for(int i = 1; i < n; ++i){if(pos[i] - st >= k){++cnt;if(cnt >= c)return true;st = pos[i];}}return false;}int Binary_search(int left, int right) /// 二分枚举满足条件的最大距离{while(left <= right){int mid = (left + right) >> 1;if(judge(mid)) /// 所求距离 >= mid,可以继续增大试探left = mid+1;else /// 所求距离 < mid,所以必须减小来试探right = mid-1;}return left-1;}int main(){while(~scanf("%d%d", &n, &c)){for(int i = 0; i < n; ++i)scanf("%d", &pos[i]);sort(pos, pos+n);printf("%d\n", Binary_search(0, pos[n-1] - pos[0]));}return 0;}NYOJ 摘枇杷(最大值最小化)理工学院的枇杷快熟了,ok,大家都懂得。
ACM 算法模板
ACM Standard Code LibraryHuang WeiComputer Science and EngineeringAssociation of ProgramingInformation Engineering CollegeHangzhou Dianzi UniversityApril, 2007ACM 算法模板集Contents一.常用函数与STL二.重要公式与定理1. Fibonacci Number2. Lucas Number3. Catalan Number4. Stirling Number(Second Kind)5. Bell Number6. Stirling's Approximation7. Sum of Reciprocal Approximation8. Young Tableau9. 整数划分10. 错排公式11. 三角形内切圆半径公式12. 三角形外接圆半径公式13. 圆內接四边形面积公式14. 基础数论公式三.大数模板四.数论算法1. Greatest Common Divisor最大公约数2. Prime素数判断3. Sieve Prime素数筛法4. Module Inverse模逆元5. Extended Euclid扩展欧几里德算法6. Modular Linear Equation模线性方程(同余方程)7. Chinese Remainder Theorem中国余数定理五.图论算法1. 最小生成树(Kruscal算法)2. 最小生成树(Prim算法)3. 单源最短路径(Bellman-ford算法)4. 单源最短路径(Dijkstra算法)5. 全源最短路径(Folyd算法)6. 拓扑排序7. 网络预流和最大流8. 网络最小费用最大流9. 网络最大流(高度标号预流推进)10. 最大团11. 最大二分图匹配(匈牙利算法)六.几何算法1. 几何模板2. 球面上两点最短距离3. 三点求圆心坐标七.专题讨论1. 树状数组2. 字典树3. 后缀树4. 线段树5. 并查集6. 二叉堆7. 逆序数(归并排序)8. 树状DP9. 欧拉路10. 八数码11. 高斯消元法12. 字符串匹配(KMP算法)13. 全排列,全组合第一章常用函数和STL一.常用函数#include <stdio.h>int getchar( void ); //读取一个字符, 一般用来去掉无用字符char *gets( char *str ); //读取一行字符串#include <stdlib.h>void * malloc( size_t size ); //动态内存分配, 开辟大小为 size 的空间void qsort( void *buf, size_t num, size_t size, int (*compare)(const void *, const void *) ); //快速排序Sample:int compare_ints( const void* a, const void* b ){int* arg1 = (int*) a; int* arg2 = (int*) b;if( *arg1 < *arg2 ) return -1;else if( *arg1 == *arg2 ) return 0;else return 1;}int array[] = { -2, 99, 0, -743, 2, 3, 4 }; int array_size = 7;qsort( array, array_size, sizeof(int), compare_ints );#include <math.h>//求反正弦, arg∈[-1, 1], 返回值∈[-pi/2, +pi/2]double asin( double arg );//求正弦, arg为弧度, 弧度=角度*Pi/180.0, 返回值∈[-1, 1]double sin( double arg );//求e的arg次方double exp( double arg );//求num的对数, 基数为edouble log( double num );//求num的根double sqrt( double num );//求base的exp次方double pow( double base, double exp );#include <string.h>//初始化内存, 常用来初始化数组void* memset( void* buffer, int ch, size_t count );memset( the_array, 0, sizeof(the_array) );//printf是它的变形, 常用来将数据格式化为字符串int sprintf( char *buffer, const char *format, ... );sprintf(s, "%d%d", 123, 4567); //s="1234567"//scanf是它的变形, 常用来从字符串中提取数据int sscanf( const char *buffer, const char *format, ... );Sample:char result[100]="24 hello", str[100]; int num;sprintf( result, "%d %s", num,str );//num=24;str="hello" ;//字符串比较, 返回值<0代表str1<str2, =0代表str1=str2, >0代表str1>str2 int strcmp( const char *str1, const char *str2 );二.常用STL[标准container概要]vector<T> 大小可变的向量, 类似数组的用法, 容易实现删除list<T> 双向链表queue<T> 队列, empty(), front(), pop(), push()stack<T> 栈, empty(), top(), pop(), push()priority_queue<T> 优先队列, empty(), top(), pop(), push()set<T> 集合map<key,val> 关联数组, 常用来作hash映射[标准algorithm摘录]for_each() 对每一个元素都唤起(调用)一个函数find() 查找第一个能与引数匹配的元素replace() 用新的值替换元素, O(N)copy() 复制(拷贝)元素, O(N)remove() 移除元素reverse() 倒置元素sort() 排序, O(N log(N))partial_sort() 部分排序binary_search() 二分查找merge() 合并有序的序列, O(N)[C++ String摘录]copy() 从别的字符串拷贝empty() 判断字符串是否为空erase() 从字符串移除元素find() 查找元素insert() 插入元素length() 字符串长度replace() 替换元素substr() 取子字符串swap() 交换字符串第二章重要公式与定理1.Fibonacci Number0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610 …Formula:2.Lucas Number1, 3, 4, 7, 11, 18, 29, 47, 76, 123...Formula:3.Catalan Number1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012…Formula:Application:1)将n + 2 边形沿弦切割成n个三角形的不同切割数Sample:n = 2;n = 3;2)n + 1个数相乘, 给每两个元素加上括号的不同方法数Sample:n = 2; (1 (2 3)), ((1 2) 3)n = 3; (1 (2 (3 4))), (1 ((2 3) 4)) , ((1 2) (3 4)), ((1 (2 3)) 4), (((1 2) 3) 4)3)n 个节点的不同形状的二叉树数(严《数据结构》P.155)4)从n * n 方格的左上角移动到右下角不升路径数Sample:n = 2;n = 3;4.Stirling Number(Second Kind)S(n, m)表示含n个元素的集合划分为m个集合的情况数或者是n个有标号的球放到m 个无标号的盒子中, 要求无一为空, 其不同的方案数Formula:Special Cases:5.Bell Numbern 个元素集合所有的划分数Formula:6.Stirling's Approximation7.Sum of Reciprocal ApproximationEulerGamma = 0.57721566490153286060651209;8.Young TableauYoung Tableau(杨式图表)是一个矩阵, 它满足条件:如果格子[i, j]没有元素, 则[i+1, j]也一定没有元素如果格子[i, j]有元素a[i, j],则[i+1, j]要么没有元素, 要么a[i+1, j] > a[i, j] Y[n]代表n个数所组成的杨式图表的个数Formula:Sample:n = 3;9.整数划分将整数n分成k份, 且每份不能为空, 任意两种分法不能相同1) 不考虑顺序for(int p=1; p<=n ;p++)for(int i=p; i<=n ;i++)for(int j=k; j>=1 ;j--)dp[i][j] += dp[i-p][j-1];cout<< dp[n][k] <<endl;2) 考虑顺序dp[i][j] = dp[i-k][j-1]; (k=1..i)3) 若分解出来的每个数均有一个上限mdp[i][j] = dp[i-k][ j-1]; (k=1..m)10.错排公式11.三角形内切圆半径公式12.三角形外接圆半径公式13.圆內接四边形面积公式14.基础数论公式1)模取幂2) n的约数的个数若n满足, 则n的约数的个数为第三章大数模板/**** **** **** **** **** ***** Function Name : BigNumber* Description : BigNumber's HPC* Author : HuangWei* Last Edited : 07.4.11**** **** **** **** **** ****/#include <iostream>#include <string>#include <sstream>#include <memory>#include <algorithm>#define BASE 1000 // 基数#define DIG 1100 // 存储using namespace std;class BigNumber{private:int data[DIG]; // 数据区int len; // 记录长度public:BigNumber() {len=1;memset(data,0,sizeof(data));data[0]=1;}BigNumber(int); // 输入默认十进制BigNumber(char*);BigNumber(const BigNumber &);// 类型转换BigNumber & Num_BNum(int); //把一个整数转换成BigNumber型的BigNumber & Str_BNum(char*); //把一个字符串类型的转换成BigNumber型的int Int();string Str();// HPCBigNumber & Add(const BigNumber &);BigNumber & Sub(const BigNumber &);BigNumber & Mul(const BigNumber &);BigNumber & Div(int);BigNumber & Mod(int);BigNumber & operator=(const BigNumber &);int Bigger(const BigNumber &) const;BigNumber operator + (const BigNumber &);BigNumber operator - (const BigNumber &);BigNumber operator * (const BigNumber &);BigNumber operator / (int);BigNumber operator % (int);BigNumber & operator += (const BigNumber &); BigNumber & operator -= (const BigNumber &); BigNumber & operator *= (const BigNumber &); BigNumber & operator /= (int);BigNumber & operator %= (int);};BigNumber & BigNumber::Num_BNum(int b){len=1; memset(data,0,sizeof(data));data[0] = 1;if(b < 0) {b = -b;data[0] = -1;}while(b > 0) {data[ len++ ] = b % BASE;b /= BASE;}return *this;}BigNumber & BigNumber::Str_BNum(char* sb) {int t=0, d=1, b=0, slen=strlen(sb), i;len=1; memset(data,0,sizeof(data));data[0] = 1;if(sb[0] == '-') data[0] = -1, b=1;for(i=slen-1; i>=b ;i--) {while(t >= BASE || d > BASE) {data[ len++ ] = t % BASE;t /= BASE;d = 10;}t += (sb[i]-'0') * d;d *= 10;}while(t > 0) {data[ len++ ] = t % BASE;t /= BASE;}return *this;}int BigNumber::Int(){istringstream sin;int v;sin.str( this->Str() );sin >> v;return v;} //这个函数的用法还是第一次看到,没看懂string BigNumber::Str(){int i,base_len=0;ostringstream sout;if(len == 1) {sout << '0';//sout << endl;return sout.str();}if(data[0] < 0) sout << "-";sout << data[len-1];i = BASE;while(i > 1) {base_len++;i /= 10;}for(i=len-2; i>0 ;i--) {sout.width(base_len);sout.fill('0');sout << data[i];}//sout << endl;return sout.str();} //这个函数也没有看懂BigNumber::BigNumber(int b){this->Num_BNum(b);}BigNumber::BigNumber(char* sb){this->Str_BNum(sb);}// -1 a<b, 0 a==b, 1 a>bBigNumber::BigNumber(const BigNumber & b){len = b.len; memcpy(data,b.data,sizeof(data));}int BigNumber::Bigger(const BigNumber & b) const {int i,flag;if(data[0] ==1 && b.data[0] ==1) flag = 1;else if(data[0] ==1 && b.data[0] ==-1) return 1;else if(data[0] ==-1 && b.data[0] ==1) return -1;else flag = -1;if(len > b.len) return flag;else if(len == b.len) {for(i=len-1; i>0 ;i--)if(data[i] > b.data[i]) return flag;}if(i == 0) return 0;return -flag;} //比较函数BigNumber & BigNumber::Add(const BigNumber & b) {int i;if(data[0] * b.data[0] != 1) {data[0] = -data[0];Sub(b);data[0] = -data[0];return *this;}len= len > b.len ? len : b.len;for(i=1; i<len ;i++) {data[i] += b.data[i];if(data[i] >= BASE) {data[i+1]++;data[i] -= BASE;}}if(data[i] > 0) len = i+1;return *this;} //加上b这个大数BigNumber & BigNumber::Sub(const BigNumber & b) {int i;if(data[0] * b.data[0] != 1) {data[0] = -data[0];Add(b);data[0] = -data[0];return *this;}len= len > b.len ? len : b.len;for(i=1; i<len ;i++) {data[i] -= b.data[i];if(data[i] < 0) {data[i+1]--;data[i] += BASE;}}if(data[len] < 0) {for(i=0; i<=len ;i++)data[i] = -data[i];for(i=1; i<len ;i++)if(data[i] < 0) {data[i+1]--;data[i] += BASE;}}while(data[len-1] == 0) len--;return *this;}BigNumber & BigNumber::Mul(const BigNumber & b) {BigNumber bt;int i,j,up;int temp,temp1;bt.data[0] = data[0] * b.data[0];for(i=1; i<len ;i++) {up = 0;for(j=1; j<b.len ;j++) {temp = data[i] * b.data[j] + bt.data[i+j-1] + up;if(temp >= BASE) {temp1 = temp % BASE;up = temp / BASE;bt.data[i+j-1] = temp1;}else {up = 0;bt.data[i+j-1] = temp;}}if(up != 0) bt.data[i+j-1] = up;}bt.len = i+j;while(bt.data[bt.len-1] == 0) bt.len--;*this=bt;return *this;}BigNumber & BigNumber::Div(int b){BigNumber bt;int i,down = 0;if(b < 0) bt.data[0] = -data[0] , b = -b;else bt.data[0] = data[0];for(i=len-1; i>=1 ;i--) {bt.data[i] = (data[i] + down * BASE) / b;down = data[i] + down * BASE - bt.data[i] * b;}bt.len = len;while(bt.data[bt.len-1] == 0) bt.len--;*this=bt;return *this;}BigNumber & BigNumber::Mod(int b){int temp = 0, up = 0, i;for(i=len-1; i>=1 ;i--) {temp = data[i];temp += up * BASE;up = temp % b;}if(data[0] < 0) up = -up;*this = up;return *this;}BigNumber & BigNumber::operator = (const BigNumber & b) {len = b.len; memcpy(data,b.data,sizeof(data)); return *this;}BigNumber BigNumber::operator + (const BigNumber & b) {BigNumber bt=*this; return bt.Add(b);}BigNumber BigNumber::operator - (const BigNumber & b) {BigNumber bt=*this; return bt.Sub(b);}BigNumber BigNumber::operator * (const BigNumber & b) {BigNumber bt=*this; return bt.Mul(b);}BigNumber BigNumber::operator / (int b){BigNumber bt=*this; return bt.Div(b);}BigNumber BigNumber::operator % (int b){BigNumber bt=*this; return bt.Mod(b);}BigNumber & BigNumber::operator += (const BigNumber & b) {return this->Add(b);}BigNumber & BigNumber::operator -= (const BigNumber & b) {return this->Sub(b);}BigNumber & BigNumber::operator *= (const BigNumber & b) {return this->Mul(b);}BigNumber & BigNumber::operator /= (int b){return this->Div(b);}BigNumber & BigNumber::operator %= (int b){return this->Mod(b);}第四章数论算法1.Greatest Common Divisor最大公约数int GCD(int x, int y){int t;while(y > 0) {t = x % y;x = y;y = t;}return x;}2.Prime素数判断bool is_prime(int u){if(u == 0 || u == 1) return false;if(u == 2) return true;if(u%2 == 0) return false;for(int i=3; i <= sqrt(u) ;i+=2)if(u%i==0) return false;return true;}3.Sieve Prime素数筛法const int M = 1000; // M : sizebool mark[M]; // true : prime numbervoid sieve_prime(){memset(mark, true, sizeof(mark));mark[0] = mark[1] = false;for(int i=2; i <= sqrt(M) ;i++) {if(mark[i]) {for(int j=i*i; j < M ;j+=i)mark[j] = false;}}}4.Module Inverse模逆元// ax ≡ 1 (mod n)int Inv(int a, int n){int d, x, y;d = extended_euclid(a, n, x, y);if(d == 1) return (x%n + n) % n;else return -1; // no solution}5.Extended Euclid扩展欧几里德算法//如果GCD(a,b) = d, 则存在x, y, 使d = ax + by// extended_euclid(a, b) = ax + byint extended_euclid(int a, int b, int &x, int &y){int d;if(b == 0) {x = 1; y = 0; return a;}d = extended_euclid(b, a % b, y, x);y -= a / b * x;return d;}6.Modular Linear Equation模线性方程(同余方程) //如果GCD(a, b)不能整除c, 则ax + by = c 没有整数解// ax ≡ b (mod n) n > 0//上式等价于二元一次方程ax – ny = bvoid modular_linear_equation(int a, int b, int n){int d, x, y, x0;d = extended_euclid(a, n, x, y);if( b%d == 0) {x0 = ( x*(b/d) ) % n; // x0 : basic solutionint ans = n;for(int i=0; i < d ;i++) {ans = ( x0 + i*(n/d) ) % n;cout << ans << endl;}}else cout << "no solution" << endl;}7.Chinese Remainder Theorem中国余数定理// x ≡ b[i] (mod w[i]), i∈[1, len-1]// 前提条件w[i] > 0, 且w[]中任意两个数互质int chinese_remainder(int b[], int w[], int len){int i, d, x, y, m, n;x = 0; n = 1;for(i=0; i < len ;i++) n *= w[i];for(i=0; i < len ;i++) {m = n / w[i] ;d = extended_euclid(w[i], m, x, y);x = (x + y*m*b[i]) % n;}return (n + x%n) % n;}第五章图论算法1.最小生成树(Kruscal算法)/**** **** **** **** **** ***** Function Name : 最小生成树(Kruscal算法)* Description : ZJU 1203 Swordfish O(E*LogE)**** **** **** **** **** ****/#include <iostream>#include <algorithm>#include <cstdio>#include <cmath>using namespace std;struct struct_edges{int bv,tv; //bv 起点 tv 终点double w; //权值};struct_edges edges[10100]; //边集struct struct_a{double x;double y;};struct_a arr_xy[101];int point[101],n,e; //n 顶点数, e 边数(注意是无向网络)double sum;int kruscal_f1(int point[], int v){int i = v;while(point[i] > 0) i = point[i];return i;}bool UDlesser(struct_edges a, struct_edges b){return a.w < b.w;}void kruscal() //只需要准备好n,e,递增的边集edges[]即可使用{int v1,v2,i,j;for(i=0; i<n ;i++) point[i]=0;i = j = 0;while(j<n-1 && i<e) {v1 = kruscal_f1(point, edges[i].bv);v2 = kruscal_f1(point, edges[i].tv);if(v1 != v2) {sum += edges[i].w; //注意sum初始为0point[v1]=v2;j++;}i++;}}int main(){int k,i,j;cin>>n;k=0;while(n != 0) {sum=0;k++;for(i=0; i<n ;i++)cin>>arr_xy[i].x>>arr_xy[i].y;e=0;for(i=0; i<n ;i++) //从0开始计数for(j=i+1; j<n ;j++) //注意是无向网络{if(i == j) continue;edges[e].bv=i;edges[e].tv=j;edges[e].w=sqrt((arr_xy[i].x-arr_xy[j].x)*(arr_xy[i].x-arr_xy[j].x)+( arr_xy[i].y-arr_xy[j].y)*(arr_xy[i].y-arr_xy[j].y));e++;}sort(edges,edges+e,UDlesser); //得到一个递增的边集,注意是从0开始计数kruscal();printf("Case #%d:\n",k); //cout<<"Case #"<<k<<":"<<endl;printf("The minimal distance is: %.2f\n",sum); //输出sumcin>>n;if(n != 0) printf("\n");}}2.最小生成树(Prim算法)/**** **** **** **** **** ***** Function Name : 最小生成树(Prim算法)* Description : ZJU 1203 Swordfish O(N^2)**** **** **** **** **** ****/#include <iostream>#include <cmath>#include <cstdio>using namespace std;double sum, arr_list[101][101], min;int i, j, k=0, n;struct struct_a{float x;float y;};struct_a arr_xy[101];struct struct_b{int point;float lowcost;};struct_b closedge[101];void prim(int n) //prim 需要准备:n顶点数 arr_list[][]顶点的邻接矩阵也是从0开始计数{int i,j,k;k=0;for(j=0; j<n ;j++) {if(j != k) {closedge[j].point = k;closedge[j].lowcost = arr_list[k][j];}}closedge[k].lowcost=0;for(i=0; i<n ;i++) {min=10000;for(j=0; j<n ;j++) {if (closedge[j].lowcost != 0 && closedge[j].lowcost < min) {k = j;min = closedge[j].lowcost;}}sum += closedge[k].lowcost; //不要改成sum+=min; sum即为所求值 closedge[k].lowcost = 0;for(j=0; j<n ;j++) {if(arr_list[k][j] < closedge[j].lowcost) {closedge[j].point = k;closedge[j].lowcost = arr_list[k][j];}}}}/*arr_list[][]= Wij 如果Vi, Vj有边0 如果i=j无限大如果没有边*/int main(){cin>>n;while(n != 0) {sum=0;k++;for(i=0; i<n ;i++)cin>>arr_xy[i].x>>arr_xy[i].y;for(i=0; i<n ;i++)for(j=0; j<n ;j++) //得到邻接矩阵arr_list[][]arr_list[i][j]=arr_list[j][i]=sqrt((arr_xy[i].x-arr_xy[j].x)*(arr_xy[i].x-arr_xy[j].x)+(arr_xy[i].y-arr_xy[j].y)*(arr_xy[i].y-arr_xy[j].y));prim(n);cout<<"Case #"<<k<<":"<<endl;printf("The minimal distance is: %.2f\n",sum);cin>>n;if(n!=0) printf("\n");}}3.单源最短路径(Bellman-ford算法)/**** **** **** **** **** ***** Function Name : 单源最短路径(Bellman-ford算法)* Description : 可允许有负权**** **** **** **** **** ****/#include <stdio.h>#define MAX 100#define MAXNUM 1000000typedef struct graphnode{int vexnum; //顶点数int arcnum; //边数int gra[MAX][MAX]; //图}Graph;Graph *G;//arc数组中存储的第一个顶点到其他顶点的最短路径//结果存在dis数组中int dis[MAX];int arc[MAX][MAX];void bellman(Graph *G){int i,j;bool sign;for(i=0; i < G->vexnum ;i++) dis[i]=MAXNUM;dis[1] = 0;sign = true;for(i=1; i < G->vexnum ;i++) {sign = false;for(j=0; j < G->arcnum ;j++) {if(dis[ arc[j][0] ] < MAXNUM&& dis[ arc[j][1] ] > dis[ arc[j][0] ] + G->gra[ arc[j][0] ][ arc[j][1] ]) {dis[ arc[j][1] ]=dis[ arc[j][0] ] + G->gra[ arc[j][0] ][ arc[j][1] ];sign = true;}}}return;}4.单源最短路径(Dijkstra算法)/**** **** **** **** **** ***** Function Name : 单源最短路径 (Dijkstra算法)* Description : 贪心, O(N^2), 不能有负权**** **** **** **** **** ****/int matrix[200][200],n; //matrix[][], 30000表示无限大,即无边.否则为有边,其值为边的权值void Dijkstra(int x,int y) //起点Vx 终点Vy{int i,j,k,path[40000],mark[40000];int min,dist[40000];for(i=1;i<=n;i++) {mark[i] = 0;dist[i] = matrix[x][i];path[i] = x;}mark[x] = 1;do {min=30000;k=0;for(i=1;i<=n;i++)if(mark[i]==0 && dist[i]<min) {min = dist[i];k = i;}if(k) {mark[k] = 1;for(i=1;i<=n;i++)if(matrix[k][i]<30000 && min+matrix[k][i]<dist[i]) {dist[i] = min + matrix[k][i];path[i] = k;}}}while(k);cout<<dist[y]<<endl; //dist[y] 的值就是从Vx 到 Vy 的最短路径值//如果希望得到路径,加入如下代码:do {cout<<k<<"<--";k = path[k];}while(k!=x);cout<<x<<endl;}5.全源最短路径(Folyd算法)/**** **** **** **** **** ***** Function Name : 全源最短路径(Folyd算法)* Description : DP, O(N^3)**** **** **** **** **** ****///初始化//min_graph[i][j]=graph[i][j];//path[i][j]=j;void Floyd(){int i,j,k;for(k=0;k<vertex_number;k++) {for(i=0;i<vertex_number;i++) {for(j=0;j<vertex_number;j++) {if((graph[i][k]==-1) || (graph[k][j]==-1)) continue;if((min_graph[i][j]==-1) || (min_graph[i][j] > graph[i][k]+graph[k][j])) {min_graph[i][j] = graph[i][k]+graph[k][j]; /*最短路径值*/path[i][j] = k; /*最短路径*/}}}}}6.拓扑排序/**** **** **** **** **** ***** Function Name : 拓扑排序**** **** **** **** **** ****///degree[] 每个结点的入度//f[] 每个结点所在的层void Toplogical_sort(){int i,j;bool p=true;top=0;while(p) {p=false;top++;for(i=1;i<=n;i++)if(degree[i]==0) {p=true;f[i]=top;}for(i=1;i<=n;i++)if(f[i]==top) {for(j=1;j<=n;j++)if(map[i][j]) degree[j]--;degree[i]=-1;}}top--;}7.网络预流和最大流int rel[1000][10000]; //全局变量int pre[1000];//计算网络流//如果是二分图的匹配, 可以先对其进行网络预流以简化后续的查找int pre_flow(int n,vector<int> * v){int ret = 0;int i,j,t,t1;for(i = 0 ; i < v[0].size() ; i++){t = v[0][i]; //t是与节点0相邻接的点for(j = 0 ; j < v[t].size() ; j++){t1 = v[t][j]; //与t相邻接的点if(rel[t1][n - 1] > 0){ret++;rel[0][t]--, rel[t][0]++;rel[t][t1]--, rel[t1][t]++;rel[t1][n - 1]--, rel[n - 1][t1]++;break;}}}return ret;}/*网络中求最大流参数含义: n代表网络中节点数,第0节点为源点, 第n-1节点为汇点rel是个二维数组, rel[i][j]代表从节点i到节点j的流量v[]是一个节点数组, v[i]包含与节点i相邻接的所有节点返回值: 最大流量*/int max_flow(int n,vector<int> * v){int ret = 0,i;int t,t1,tm;queue<int> q;const int Infinite = 2000000000;while(1){for(t = 0 ; t < n ; t++) pre[t] = -1;while(!q.empty()) q.pop();q.push(0);while(!q.empty()){ //find a augmenting path using breath-first searcht = q.front();q.pop();if(t == n - 1) break; //到达汇点for(i = 0 ; i < v[t].size() ; i++){ //对于t相邻接的所有点查找可行路径 t1 = v[t][i];if(rel[t][t1] > 0 && pre[t1] == -1){pre[t1] = t;q.push(t1);}}}if(q.empty() && t != n - 1) break;tm = Infinite; //此处寻找路径最小值在二分图中可省略while(t != 0){ //find the minimal num in the patht1 = pre[t];if(rel[t1][t] < tm) tm = rel[t1][t];t = t1;}// tm = 1; //二分图中t = n - 1;while(t != 0){ //change the relationt1 = pre[t];rel[t1][t] -= tm;rel[t][t1] += tm;t = t1;}ret += tm;}return ret;}8.网络最小费用最大流/**** **** **** **** **** ****网络中最小费用最大流参数含义: np代表网络中的总节点数, v是网络节点的邻接表cost为最后求得的最小费用, mf为求得的最大流算法: 初始最小费用及最大流均为0,不断寻找可增广路增广路对应的单位费用最小并且可流修改残留网络及cost,mf. 直到无可增广路为止。
ACM数论模板
目录目录 (1)一.扩展的欧几里德和不定方程的解 (2)二.中国同余定理 (3)三.原根 (5)四.积性函数 (6)五.欧拉函数性质 (7)六.线性求1-max的欧拉函数值 (9)七.求单个欧拉函数,求最小的x(phi(n)%x==0),使得2^x =1(mod n) (10)一.扩展的欧几里德和不定方程的解解不定方程ax + by = n的步骤如下:(1)计算gcd(a, b). 若gcd(a, b)不能整除n,则方程无整数解;否则,在方程的两边同除以gcd(a, b),得到新的不定方程a'x + b'y = n',此时gcd(a', b') = 1(2)求出不定方程a'x + b'y = 1的一组整数解x0, y0,则n'x0,n'y0是方程a'x + b'y = n'的一组整数解。
(3)根据扩展欧几里德定理,可得方程a'x + b'y = n'的所有整数解为:x = n'x0 + b'ty = n'y0 - a't(t为整数)这也就是方程ax + by = n的所有整数解利用扩展的欧几里德算法,计算(a, b)和满足gcd = (a, b) = ax0 + by0的x0和y0,也就是求出了满足a'x0 + b'y0 = 1的一组整数解。
因此可得:x = n/gcd * x0 + b/gcd * ty = n/gcd * y0 - a/gcd * t(t是整数)int extend_Euclid(int a, int b, int &x, int &y){if (b == 0){x = 1;y = 0;return a;}int gcd= extend_Euclid ( b, a % b, x, y );int temp = x;x = y;y = temp - (a / b) * y;return gcd;}二.中国同余定理Poj 2891#include<stdio.h>#include<iostream>using namespace std;__int64 GCD(__int64 i,__int64 j){if(j==0)return i;elsereturn GCD(j,i%j);}__int64 extend_Euclid(__int64 a, __int64 b, __int64 &x, __int64 &y) {if (b == 0){x = 1;y = 0;return a;}__int64 gcd= extend_Euclid ( b, a % b, x, y );__int64 temp = x;x = y;y = temp - (a / b) * y;return gcd;}//只有两个式子的中国同余定理,return z=a*xx+x=b*yy+y;__int64 CRT_2(__int64 a,__int64 x,__int64 b,__int64 y){__int64 xx,yy,gcd;gcd=extend_Euclid(a,b,xx,yy);__int64 c=y-x;while(c<0)c+=a;if(c%gcd!=0)return -1;xx*=c/gcd;yy*=c/gcd;__int64 t=yy/(a/gcd);while(yy-t*(a/gcd)>0)t++;while(yy-(t-1)*(a/gcd)<=0)t--;return (t*(a/gcd)-yy)*b+y;}//chinese remainder theorem//crt[i][0]存的是除数,crt[i][1]存的是余数,0<=i<n,n>1,返回结果,-1表示无解__int64 CRT(__int64 crt[][2],int n){__int64 m=crt[0][0]/GCD(crt[0][0],crt[1][0])*crt[1][0]; //最大公约数__int64 ans=CRT_2(crt[0][0],crt[0][1],crt[1][0],crt[1][1])%m;for(int i=2;i<n&&ans!=-1;i++){ans=CRT_2(m,ans,crt[i][0],crt[i][1]);m*=crt[i][0]/GCD(m,crt[i][0]);ans%=m;}return ans;}int main(void){int n;__int64 a[10000][2];while(scanf("%d",&n)==1){for(int i=0;i<n;i++)scanf("%I64d%I64d",&a[i][0],&a[i][1]);if(n==1)printf("%I64d\n",a[0][1]);elseprintf("%I64d\n",CRT(a,n));}return 0;}三.原根Poj 1284 ans=φ(p-1);//p是素数设h为一整数,n为一正整数,(h,n)=k,适合h^k=1(mod n)的最小正整数k叫做h对n的次数。
个人整理 ACM 模板
0.头文件#define _CRT_SBCURE_NO_DEPRECATE #include <set>#include <cmath>#include <queue>#include <stack>#include <vector>#include <string>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>#include <functional>using namespace std;const int maxn = 110;1.const int INF = 0x3f3f3f3f;经典1.埃拉托斯特尼筛法/*|埃式筛法||快速筛选素数||16/11/05ztx|*/int prime[maxn];bool is_prime[maxn];int sieve(int n){int p = 0;for(int i = 0; i <= n; ++i)is_prime[i] = true;is_prime[0] = is_prime[1] = false;for (int i = 2; i <= n; ++i){ // 注意数组大小是nif(is_prime[i]){prime[p++] = i;for(int j = i + i; j <= n; j += i) // 轻剪枝,j必定是i的倍数is_prime[j] = false;}}return p; // 返回素数个数}2.快速幂/*|快速幂||16/11/05ztx|*/typedef long long LL; // 视数据大小的情况而定LL powerMod(LL x, LL n, LL m){LL res = 1;while (n > 0){if (n & 1) // 判断是否为奇数,若是则true res = (res * x) % m;x = (x * x) % m;n >>= 1; // 相当于n /= 2;}..return res;}3.大数模拟大数加法/*|大数模拟加法||用string模拟||16/11/05ztx, thanks to caojiji|*/string add1(string s1, string s2){if (s1 == "" && s2 == "") return"0";if (s1 == "") return s2;if (s2 == "") return s1;string maxx = s1, minn = s2;if (s1.length() < s2.length()){maxx = s2;minn = s1;}int a = maxx.length() - 1, b = minn.length() - 1;for (int i = b; i >= 0; --i){maxx[a--] += minn[i] - '0'; // a一直在减,额外还要减个'0'}for (int i = maxx.length()-1; i > 0;--i){ if (maxx[i] > '9'){maxx[i] -= 10;//注意这个是减10maxx[i - 1]++;}}if (maxx[0] > '9'){maxx[0] -= 10;maxx = '1' + maxx;}return maxx;}大数阶乘/*|大数模拟阶乘||用数组模拟||16/12/02ztx|*/#include <iostream>#include <cstdio>using namespace std;typedef long long LL;const int maxn = 100010;int num[maxn], len;/*在mult函数中,形参部分:len每次调用函数都会发生改变,n 表示每次要乘以的数,最终返回的是结果的长度tip: 阶乘都是先求之前的(n-1)!来求n!初始化Init函数很重要,不要落下*/void Init() {num[0] = 1;}int mult(int num[], int len, int n) {LL tmp = 0;for(LL i = 0; i < len; ++i) {tmp = tmp + num[i] * n; //从最低位开始,等号左边的tmp表示当前位,右边的tmp表示进位(之前进的位)num[i] = tmp % 10; // 保存在对应的数组位置,即去掉进位后的一位数tmp = tmp / 10; // 取整用于再次循环,与n和下一个位置的乘积相加}while(tmp) { // 之后的进位处理num[len++] = tmp % 10;tmp = tmp / 10;}return len;}int main() {int n;n = 1977; // 求的阶乘数for(int i = 2; i <= n; ++i) {len = mult(num, len, i);}for(int i = len - 1; i >= 0; --i)printf("%d",num[i]); // 从最高位依次输出,数据比较多采用printf输出printf("\n");return0;}4.GCD/*|辗转相除法||欧几里得算法||求最大公约数||16/11/05ztx|*/int gcd(int big, int small){if (small > big) swap(big, small);int temp;while (small != 0){ // 辗转相除法if (small > big) swap(big, small); temp = big % small;big = small;small = temp;}return(big);}5.LCM/*|辗转相除法||欧几里得算法||求最小公倍数||16/11/05ztx|*/int gcd(int big, int small){if (small > big) swap(big, small);int temp;while (small != 0){ // 辗转相除法if (small > big) swap(big, small);temp = big % small;big = small;small = temp;}return(big);}6.全排列/*|求1到n的全排列, 有条件||16/11/05ztx, thanks to wangqiqi|*/void Pern(int list[], int k, int n) { // k表示前k 个数不动仅移动后面n-k位数if (k == n - 1) {for (int i = 0; i < n; i++) {printf("%d", list[i]);}printf("\n");}else {for (int i = k; i < n; i++) { // 输出的是满足移动条件所有全排列swap(list[k], list[i]);Pern(list, k + 1, n);swap(list[k], list[i]);}}}7.二分搜索/*|二分搜索||要求:先排序||16/11/05ztx, thanks to wangxiaocai|*/// left为最开始元素, right是末尾元素的下一个数,x是要找的数int bsearch(int *A, int left, int right, int x){int m;while (left < right){m = left + (right - left) / 2;if (A[m] >= x) right = m; else left = m + 1;// 如果要替换为 upper_bound, 改为:if(A[m] <= v) x = m+1; else y = m;}return left;}/*最后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, thanks to chaixiaojun|*/int father[maxn]; // 储存i的father父节点void makeSet() {for (int i = 0; i < maxn; i++)father[i] = i;}int findRoot(int x) { // 迭代找根节点int root = x; // 根节点while (root != father[root]) { // 寻找根节点root = father[root];}while (x != root) {int tmp = father[x];father[x] = root; // 根节点赋值x = tmp;}return root;}void Union(int x, int y) { // 将x所在的集合和y所在的集合整合起来形成一个集合。
ACM常用算法介绍及实用模板
河南大学ACM常用算法介绍及模板河南大学计算机与信息工程学院1一、数学问题 (7)1. 精度计算——大数阶乘 (7)2.精度计算——乘法(大数乘小数)....................................................... 错误!未定义书签。
3.精度计算——乘法(大数乘大数) (8)4.精度计算——加法 (10)5.精度计算——减法 (11)6.精度计算——除法约分 (13)7.任意进制转换 (19)8.最大公约数、最小公倍数 (21)9.组合序列 (22)10.Ronberg算法计算积分 (25)11.行列式计算 (26)12.求排列组合数 (27)二、计算几何 (27)1.叉乘法求任意多边形面积 (28)2.求三角形面积 (29)3.求多边形重心 (30)4.两矢量间角度 (31)5.两点距离(2D、3D) (32)6.射向法判断点是否在多边形内部 (33)7.判断点是否在线段上 (35)29.判断线段与直线是否相交 (39)10.点到线段最短距离 (40)11.求两直线的交点 (42)12.判断一个封闭图形是凹集还是凸集 (43)13.Graham扫描法寻找凸包 (43)三、数论 (50)1.x的二进制长度 (50)2.返回x的二进制表示中从低到高的第i位 (51)3.模取幂运算(反复平方法求数的幂) (51)4.求解模线性方程 (54)5.求解模线性方程组(中国余数定理) (56)6.筛法素数产生器 (58)7.判断一个数是否素数 (61)8.初等数论里的欧拉公式: (61)9.数的分解 (65)10.关于数的阶乘 (67)11.母函数 (69)四、图论 (78)1. 深度优先搜索 (82)2. 边分类算法 (84)3. 连通性 (85)35. 无向图的割顶和桥 (93)6. 欧拉图 (99)1)消圈法(逐步插入回路法) (100)2)Fleury算法(能不走桥就不走桥): (104)7.最小生成树 (114)1).Prim算法(邻接矩阵,无优化): (114)2).Prim算法(邻接表+Heap优先队列优化): (116)3) Kruskal算法: (124)8.Dijkstra算法求单源最短路径 (128)1).邻接矩阵,无优化 (128)2).邻接链表,用优先队列(STL)优化 (133)9.Bellman-ford算法求单源最短路径 (138)10.Floyd-Warshall算法求每对节点间最短路径 (141)五、最大流 (143)1.最大流算法(Ford-Fulkerson) (143)2.最大二分匹配(最大流算法) (146)3.最大二分匹配(匈牙利算法) (150)4.最佳二分匹配(KM算法) (152)5.最小路径覆盖(最大流算法) (159)6.最小路径覆盖(匈牙利算法) (163)7. 关于匹配 (166)41.快速排序 (167)2.希尔排序 (168)3.选择法排序 (170)4.二分查找 (171)七.数据结构 (173)1. 并查集 (173)2. 串的匹配(KMP算法): (182)3. 字典树(字符串的储存与查找): (185)4. 二叉堆(用二叉堆排序及构建优先队列) (189)5. 二叉查找树(可作为优先队列) (194)6. 红黑树 (200)7. 树状数组 (215)1).一维数组代码(子段和): (216)2).二维数组代码(子阵和): (218)8. 线段树 (221)9. 归并树 (228)10. 后缀数组(Suffix Array) (233)八.博弈问题例题分析 (239)例1.POJ1740 A New Stone Game (240)例2.MIPT100 Nim Game -- who is the winner? (242)例3.POJ1704 Georgia and Bob (243)5例4的另种解法: (246)九.其它算法 (246)1. LCS算法 (249)2. 背包问题 (251)3. 回溯法 (256)4. RMQ问题的ST算法 (259)5. 最近公共祖先(LCA)问题 (263)1).RMQ求法 (264)2).Tarjan的脱机(离线)算法 (264)十.杂谈 (280)1.国际象棋 (280)2.STL常用结构简单用法 (280)3.图的度序列 (286)6一、数学问题1. 精度计算——大数阶乘返回值:阶乘结果的位数注意:本程序直接输出n!的结果,需要返回结果请保留long a[] 需要头文件:cmath源程序:int factorial(int n){long a[10000];int i,j,l,c,m=0,w;a[0]=1;for(i=1;i<=n;i++){c=0;for(j=0;j<=m;j++){a[j]=a[j]*i+c;c=a[j]/10000;a[j]=a[j]%10000;7if(c>0){m++;a[m]=c;}}w=m*4+(int)log10((double)a[m])+1;//阶乘的位数printf("%ld",a[m]);for(i=m-1;i>=0;i--)printf("%4.4ld",a[i]);printf("\n");return w;}2.精度计算——乘法(大数乘大数)#include<iostream>#include<sstream>using namespace std;string muling(string s1,string s2){8for(int n2=s2.length()-1;n2>=0;n2--)if(s2[n2])for(int n1=s1.length()-1,n=n2+s1.length();n1>=0;--n1,--n){int temp=(s1[n1]-'0')*(s2[n2]-'0');cheng[n-1]=char(cheng[n-1]+(cheng[n]+temp-'0')/10);cheng[n]=char((cheng[n]+temp-'0')%10+'0');}int loc=cheng.find_first_not_of('0');if(loc==-1)return"0";return cheng.substr(loc);}int main(){string s1,s2;cin>>s1>>s2;cout<<muling(s1,s2)<<endl;return 0;}9#include<sstream>#include<iostream>using namespace std;string sum(string s1,string s2){if(s1.length()<s2.length()){string temp=s1;s1=s2;s2=temp;}for(int n1=s1.length()-1,n2=s2.length ()-1;n1>=0;n1--,n2--) {s1[n1]=char(s1[n1]+(n2>=0?s2[n2]-'0':0));if(s1[n1]-'0'>=10){s1[n1]=char((s1[n1]-'0')%10+'0');if(n1)s1[n1-1]++; //想想为什么?如果不是十进制呢?elses1='1'+s1;}return s1;}int main(){for(string s1,s2;cin>>s1>>s2;) cout<<sum(s1,s2)<<endl; return 0;}4.精度计算——减法#include<sstream>#include<iostream>using namespace std;bool compare(string s1,string s2) {if(s1.length()<s2.length())return true;if(s1.length()==s2.length()){if(s1[i]<s2[i])return true;}return false;}//========================================== string subing(string s1,string s2){bool sign=0;if(s1==s2)return "0";//所以有0-0结果仍正确!if(compare(s1,s2)){string temp=s1;s1=s2;s2=temp;sign=1;}for(int n1=s1.length()-1,n2=s2.length ()-1;n1>=0;n1--,n2--){s1[n1]=char(s1[n1]-(n2>=0?s2[n2]-'0':0));{s1[n1]+=10;s1[n1-1]--;}}if(sign)return '-'+s1.substr(s1.find_first_not_of('0'));return s1.substr(s1.find_first_not_of('0'));}//==================================================== =======int main(){for(string s1,s2;cin>>s1>>s2;)cout<<subing(s1,s2)<<endl;return 0;}5.精度计算——除法约分#include<iostream>#include<sstream>//================================ typedef struct Data{string s1,s2;}Data;//两正的大数比较大小前者大返回1 相等返回0后者大返回-1 int MoreThan(string s1,string s2){if(s1.length()>s2.length())return 1;if(s1.length()<s2.length())return -1;int i;for(i=0;i<s1.length();i++){if(s1[i] != s2[i]){if(s1[i]>s2[i])return 1;elsereturn -1;}return 0;}//=============大数减法==============string OpsitionSub(string s1,string s2){。
ACM模板
ACM模板---liang一.高精度计算: ------------------------------------------------------------ 31.高精度加法:----------------------------------------------------------- 31)C++ string类实现:----------------------------------------------- 3 2)字符数组char实现:----------------------------------------------- 32.高精度减法:----------------------------------------------------------- 41)C++ string类实现:------------------------------------------------ 4 2)字符数组char实现:------------------------------------------------ 53.高精度乘法------------------------------------------------------------- 51)字符数组char实现:------------------------------------------------ 5 2)C++ string类实现:------------------------------------------------ 64.高精度阶乘(压缩五位)------------------------------------------------- 65.高精度小数加法--------------------------------------------------------- 7 二.计算几何: -------------------------------------------------------------- 81.线段相交:------------------------------------------------------------- 82.点关于直线的对称点:点:(a,b),直线:Ax+By+C=0------------------------- 93.求凸包 ---------------------------------------------------------------- 94.多边形面积------------------------------------------------------------ 115.皮克定理:------------------------------------------------------------ 116.三角形: ------------------------------------------------------------- 121)点和三角形的关系------------------------------------------------- 12 2)三角形各种面积算法:--------------------------------------------- 137.两圆相交面积---------------------------------------------------------- 14 三.搜索: ------------------------------------------------------------------ 151.DFS(深度优先、回溯) -------------------------------------------------- 152.BFS(广度优先) -------------------------------------------------------- 16 四.数论: ----------------------------------------------------------------- 171.最大公约数,最小公倍数:---------------------------------------------- 172.欧几里德扩展:-------------------------------------------------------- 173.大数除法求余、快速幂取余:-------------------------------------------- 174.同余: --------------------------------------------------------------- 195.筛素数 --------------------------------------------------------------- 19 五.图论 ------------------------------------------------------------------- 201.并查集: ------------------------------------------------------------- 202.最小生成树:---------------------------------------------------------- 201) Prim算法------------------------------------------------------- 21 2)克鲁斯卡尔算法--------------------------------------------------- 223.最短路径: ------------------------------------------------------------ 231)最短路径dijkstra算法-------------------------------------------- 23 1)Floyd算法(最短路径)------------------------------------------- 284.最大匹配 ------------------------------------------------------------- 295.最大流 --------------------------------------------------------------- 31 六.数据结构 --------------------------------------------------------------- 331.RMQ ------------------------------------------------------------------ 332.树状数组 ------------------------------------------------------------- 351)一维树状数组------------------------------------------------------ 352)二维树状数组------------------------------------------------------ 37 七.各种处理函数 ----------------------------------------------------------- 381.字符串 --------------------------------------------------------------- 381)字符串分解函数strtok-------------------------------------------- 38 八.动态规划 --------------------------------------------------------------- 391.最长公共子序列-------------------------------------------------------- 392.单调递增(递减)最长子序列-------------------------------------------- 403.整数规划:------------------------------------------------------------ 42一.高精度计算:1.高精度加法:1)C++ string类实现:#include<string>void sum(string &a,string b) // a=a+b{ int i,j,k,c,s;while (a.length()>b.length()) b='0'+b;// a,b处理成一样长 while (b.length()>a.length()) a='0'+a;c=0;for (i=a.length()-1; i>=0; i--){ s=a[i]-48+b[i]-48+c;if ( s>9 ) { s=s%10; c=1;} else c=0;a[i]=48+s;}if ( c>0 ) a='1'+a;}2)字符数组char实现:#include<string.h>void add(char a[],char b[])//a=a+b{int i,j,k,sum=0;k=strlen(a)>strlen(b)?strlen(a):strlen(b);a[k+1]=0;for(i=strlen(a)-1,j=strlen(b)-1;i>=0||j>=0;i--,j--,k--){ if(i>=0) sum+=a[i]-'0'; if(j>=0) sum+=b[j]-'0';a[k]=sum%10+'0'; sum/=10;}if(sum) a[0]=sum+'0';else strcpy(a,&a[1]);}2.高精度减法:1)C++ string类实现:#include<string>void f(string &a,string b){int i,j,sum=0;for(i=a.length()-1,j=b.length()-1;i>=0||j>=0;i--,j--){sum+=a[i]-'0'; if(j>=0) sum-=b[j]-'0';if(sum<0) {a[i]=sum+10+'0';sum=-1;}else {a[i]=sum+'0';sum=0;}}if(a[0]=='0') a=&a[1];for(i=0;a[i]=='0'&&i<a.length();i++) ;if(i==a.length()) a="0";}2)字符数组char实现:#include <string.h>void jian(char a[],char b[])//a-=b{int i,j,sum=0;for(i=strlen(a)-1,j=strlen(b)-1;i>=0||j>=0;i--,j--){sum+=a[i]-'0'; if(j>=0) sum-=b[j]-'0';if(sum<0) {a[i]=sum+10+'0';sum=-1;}else {a[i]=sum+'0';sum=0;}}if(a[0]=='0') strcpy(a,&a[1]);for(i=0;a[i]=='0';i++) ;if(i==strlen(a)) strcpy(a,"0");}3.高精度乘法1)字符数组char实现:#include <string.h>void chen(char a[],char b[])//a=a*b{ int i,j,k,l,sum,c[410]={0};l=strlen(a)+strlen(b);for(i=strlen(b)-1;i>=0;i--)for(j=strlen(a)-1,k=i+j+1;j>=0;j--,k--){ sum=(b[i]-'0')*(a[j]-'0')+c[k];c[k]=sum%10;c[k-1]+=sum/10;}for(i=c[0]?0:1,j=0;i<l;i++)a[j++]=(c[i]+'0'); a[j]=0;}2)C++ string类实现:#include<string>void chenn(string &a,string b)//a=a*b{ int i,j,k,l,sum,c[410]={0};l=a.length()+b.length();for(i=b.length()-1;i>=0;i--)for(j=a.length()-1,k=i+j+1;j>=0;j--,k--){ sum=(b[i]-'0')*(a[j]-'0')+c[k];c[k]=sum%10;c[k-1]+=sum/10;}i=c[0]?0:1;while(a.length()<l-i) a=a+'0';for(j=0;i<l;i++)a[j++]=(c[i]+'0');}4.高精度阶乘(压缩五位)#include<iostream>#include<iomanip>using namespace std;int a[10000];int main(void){int i,n,w,up,j;while(cin>>n){for(w=a[0]=i=1;i<=n;i++){ for(j=0,up=0;j<w;j++){a[j]=i*a[j]+up;up=a[j]/100000;a[j]%=100000;}if(up) a[w++]=up;}cout<<a[w-1];for(i=w-2;i>=0;i--)cout<<setfill('0')<<setw(5)<<a[i]; cout<<endl;}}5.高精度小数加法#include<cstring>#include<algorithm>void quw0(char a[]) //去除尾部多余的零 eg: 3.5+3.5=7.0变成 7 { int i;for(i=0;i<strlen(a);i++) //判断有没有小数点if(a[i]=='.') break;if(i!=strlen(a)){i=strlen(a)-1;while(a[i]=='0') {a[i]=0;;i--;}if(a[i]=='.') a[i]=0;;}}void add(char *a,char *b)//a=a+b{int i=0,j=0,la=strlen(a),lb=strlen(b),sum=0;while((a[i]-'.')&&i<la) i++;while((b[j]-'.')&&j<lb) j++;if(i==la) {a[i]='.';la++;};if(j==lb) {b[j]='.';lb++;};while(la-i>lb-j) {b[lb]='0';lb++;}while(lb-j>la-i) {a[la]='0';la++;}if(la<lb) { swap(a,b); swap(la,lb); }a[la+1]=0;b[lb]=0;for(i=la-1,j=lb-1;i>=0;i--,j--){ if(a[i]=='.') {a[i+1]='.';continue;}sum+=a[i]-'0'; if(j>=0) sum+=b[j]-'0';a[i+1]=sum%10+'0'; sum/=10;}if(sum) a[0]=sum+'0';else strcpy(a,&a[1]);quw0(a);//根据题目需要是否保留尾0}二.计算几何:1.线段相交:int xj(point x1,point x2,point x3,point x4)//相交为1,不交为0{if(min(x1.x,x2.x)>max(x3.x,x4.x)||min(x1.y,x2.y)>max(x3.y,x4.y)||min(x3.x,x4.x)>max(x1.x,x2.x)||min(x3.y,x4.y)>max(x1.y,x2.y) )return 0;//不交:矩形排斥实验,最小的>最大的肯定不交int a,b,c,d;a=(x1.x-x2.x)*(x3.y-x1.y)-(x1.y-x2.y)*(x3.x-x1.x);//跨立实验 b=(x1.x-x2.x)*(x4.y-x1.y)-(x1.y-x2.y)*(x4.x-x1.x);c=(x3.x-x4.x)*(x1.y-x3.y)-(x3.y-x4.y)*(x1.x-x3.x);d=(x3.x-x4.x)*(x2.y-x3.y)-(x3.y-x4.y)*(x2.x-x3.x);return a*b<=0&&c*d<=0;}2.点关于直线的对称点:点:(a,b),直线:Ax+By+C=0#include <stdio.h>int main(){int n;float a,b,A,B,C,a1,b1;scanf("%d\n",&n);while(n--){ scanf("%f %f %f %f %f",&a,&b,&A,&B,&C);int a1=int (a-2*A*(A*a+B*b+C)/(A*A+B*B));int b1=int (b-2*B*(A*a+B*b+C)/(A*A+B*B));printf("%d %d\n",a1,b1);}}3.求凸包//根据题目改动数据类型,数组大小,排序方式#include <algorithm>#define eps 1e-8struct point{int x,y;};point pnt[100003],res[100005];bool operator<( point A,point B )//按y排也可,具体看题目要求{ return A.x < B.x || (A.x == B.x && A.y < B.y); }double mult(point p0,point p1,point p2){ r eturn (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x); }//数组下标从0开始,n是点的个数,选中的点在保存在res数组中,个数是topint graham(point pnt[], int n, point res[])//选中的点在保存在res数组中,个数是top{ int i, len, k = 0, top = 1;sort(pnt, pnt + n); //用cmp可能超时,原因未知if (n == 0) return 0; res[0] = pnt[0];if (n == 1) return 1; res[1] = pnt[1];if (n == 2) return 2; res[2] = pnt[2];for (i = 2; i < n; i++){ while (top && mult(pnt[i], res[top], res[top-1])<=eps) top--;res[++top] = pnt[i];}len = top; res[++top] = pnt[n - 2];for (i = n - 3; i >= 0; i--){ while (top!=len && mult(pnt[i], res[top], res[top-1])<=eps) top--;res[++top] = pnt[i];}return top; // 返回凸包中点的个数}4.多边形面积//点必须是顺时针给出或逆时针给出才可用此法//使用时注意数据类型,和数据大小struct point{int x,y;}a[105];int duo(point a[],int n) //点在数组 a[]中,个数是n{ int i,s=0;for(i=1;i<=n;i++)s+=(a[i-1].x*a[i%n].y-a[i-1].y*a[i%n].x);if(s<0) s=-s;return s;// if(s%2) cout<<s/2<<".5"<<endl; 若为longl long 类型,不要用double// else cout<<s/2<<".0"<<endl;}5.皮克定理://S=a+b÷2-1//(其中a表示多边形内部的点数,b表示多边形边界上的点数,S表示多边形的面积)#include<cmath>struct point{int x,y;};int gcd(int m,int n){if(n==0) return m;return gcd(n,m%n);}int bian(point a[],int n)//算出点A和点B组成的线段上的点{ int s=0,i;for(i=1;i<=n;i++)s+=gcd(abs(a[i-1].x-a[i%n].x),abs(a[i-1].y-a[i%n].y));return s;}int duo(point a[],int n)//求n边形的面积,注意ans未除2;{int i,s=0;for(i=1;i<=n;i++)s+=(a[i-1].x*a[i%n].y-a[i-1].y*a[i%n].x);if(s<0) s=-s;return s;}6.三角形:1)点和三角形的关系//注意数据类型#include <cmath>struct point{int x,y;};bool operator ==(point A,point B){return A.x==B.x&&A.y==B.y;} int area(point A,point B,point C)//三角形面积,未除2{int s=abs((B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x));return s;}int pan3(point a[],point p) //若点在三角形内(不含边界),返回1;{int sa,sb,sc,s;s=area(a[0],a[1],a[2]);sa=area(a[0],a[1],p);sb=area(a[0],a[2],p);sc=area(a[1],a[2],p);if(sa&&sb&&sc&&s==sa+sb+sc) return 1;if((!sa||!sb||!sc)&&s==sa+sb+sc){if(p==a[0]||p==a[1]||p==a[2]) return 4;//若点在三角形顶点上,返回4。
ACM算法竞赛模板个人总结汇总
数学 (4)最大公约数、最小公倍数 (4)最大公约数——欧几里得算法O(n) (4)Stein算法O( log(max(a,b)) ) (4)最小公倍数: (4)素数相关 (5)普通素数判断 (5)筛法求素数[1,N] (5)二次筛法求素数[L,R] (6)Miller-Rabbin素数测试方法 (7)算术基本定理的定义和性质: (8)同余方程[组] 乘法模逆元中国剩余定理 (9)扩展欧几里得,求一组解x,y,使得gcd(a,b) = d = a * x + b * y (9)扩展欧几里得,求所有解x,y,使得c = a * x + b * y (10)扩展欧几里得,求a关于n的逆元a^-1,使得a * a^-1 ≡ 1(mod n) (10)扩展欧几里得,求解x,满足同余方程组x ≡ Ri(mod Ai) (10)扩展欧几里得,求解x,满足高次同余方程A^x ≡ B(mod C) (11)中国剩余定理: (13)中国剩余定理最小非负数解的算法: (14)求解a*x + b*y = c的其中一组解,使得|x| + |y|尽可能小,若相等,则a|x| + b|y|尽可能小。
(15)整数快速幂 (16)矩阵快速幂 (16)整数分解 (18)试除法整数分解 (18)筛法整数分解 (18)PollardRho大整数分解 (19)欧拉函数 (22)直接欧拉函数 (22)递推快速求欧拉函数 (23)容斥原理 (23)母函数 (24)普通母函数 (24)指数型母函数 (25)其他相关 (27)九余数定理:一个数N各位数字的和,对9取余等于这个数对9取余 (27)给你一个奇数N,求1~N的奇数平方和: S = N*(N+1)*(N+2)/6 (27)约瑟夫问题:有N个人,编号为1~N,按顺时针围成一个圈,每数k个人,就将这个人从圈中消除,问:最终只留下一个人的编号。
(27)给你整数x和y的和以及x和y的积,是否能找到满足这两个式子的整数x和整数y。
ACM动态规划问题简易模板(C++可编译)
1、0-1背包#include <stdio.h>#include <stdlib.h>//背包问题/*测试数据:输入:8 238 4 5 1 6 6 7 37 8 3 3 4 9 6 2输出:1 0 1 0 1 0 1 1*/int num,c;int v[10];int w[10];int m[10][30];//设m[i][j],则表示在前i个物品中,背包大小是j的情况下,背包所装东西的最大价值void knapsack(){int n=num-1;int jmax,i,j;if(w[n]<c) jmax=w[n];else jmax=c;for(i=0;i<jmax;i++)m[n][i]=0;for(i=w[n];i<=c;i++)m[n][i]=v[n];for(i=n-1;i>0;i--){if(w[i]<c) jmax=w[i];else jmax=c;for(j=0;j<jmax;j++)m[i][j]=m[i+1][j];for(j=w[i];j<=c;j++){if(m[i+1][j]<m[i+1][j-w[i]]+v[i])m[i][j]=m[i+1][j-w[i]]+v[i];elsem[i][j]=m[i+1][j];}}m[0][c]=m[1][c];if(c>=w[0]){if(m[0][c]<m[1][c-w[0]]+v[0])m[0][c]=m[1][c-w[0]]+v[0];}}void trackback(int *x){int n=num-1;int i;for(i=0;i<n;i++){if(m[i][c]==m[i+1][c]) x[i]=0;else{x[i]=1;c=c-w[i];}}if(m[n][c]>0) x[n]=1;else x[n]=0;}int main(){int i,x[10],j;scanf("%d %d",&num,&c);for(i=0;i<num;i++)scanf("%d",&v[i]);for(i=0;i<num;i++)scanf("%d",&w[i]);knapsack();for(i=0;i<=c;i++) printf("%3d",i);printf("\n");for(i=0;i<num;i++){for(j=0;j<=c;j++)printf("%3d",m[i][j]);printf("\n");}trackback(x);for(i=0;i<num;i++)printf("%d ",x[i]);printf("\n");return 0;}2、KMP算法#include<iostream>#include<string.h>using namespace std;inline void BuildNext(const char* pattern, size_t length, unsigned int* next){unsigned int i, t;i = 1;t = 0;next[1] = 0;while(i < length + 1){while(t > 0 && pattern[i - 1] != pattern[t - 1]){t = next[t];}++t;++i;if(pattern[i - 1] == pattern[t - 1]){next[i] = next[t];}else{next[i] = t;}}//pattern末尾的结束符控制,用于寻找目标字符串中的所有匹配结果用while(t > 0 && pattern[i - 1] != pattern[t - 1]){t = next[t];}++t;++i;next[i] = t;}unsigned int KMP(const char* text, size_t text_length, const char* pattern, size_t pattern_length, unsigned int* matches){unsigned int i, j, n;unsigned int next[pattern_length + 2];BuildNext(pattern, pattern_length, next);i = 0;j = 1;n = 0;while(pattern_length + 1 - j <= text_length - i){if(text[i] == pattern[j - 1]){++i;++j;//发现匹配结果,将匹配子串的位置,加入结果if(j == pattern_length + 1){matches[n++] = i - pattern_length;j = next[j];}}else{j = next[j];if(j == 0){++i;++j;}}//返回发现的匹配数return n;}int main(){char a[20],b[20];int n1,n2,n;unsigned int match[100];cin>>a;n1=strlen(a);//待匹配串cin>>b;n2=strlen(b);//模板串n=KMP(a,n1,b,n2,match);cout<<n<<endl;for(int i=0;i<n;i++)cout<<match[i]<<' ';}3、最大子段和#include<iostream>#include<stdio.h>using namespace std;int main(){int T,n;int a[50000];int hd[50000],tl[50000];scanf("%d",&T);while(T--){scanf("%d",&n);int i,temp,max;;for(i = 0;i < n;i++)scanf("%d",&a[i]);//hd[],left -> rightmax = hd[0] = a[0];for(i = 1;i < n;i++){temp = a[i] + hd[i - 1];hd[i] = temp > a[i] ? temp : a[i];}for(i = 1;i < n;i++){hd[i] = max > hd[i] ? max : hd[i];max = hd[i];//tl[],right -> leftmax = tl[n - 1] = a[n - 1];for(i = n - 2;i >= 0;i--){temp = a[i] + tl[i + 1];tl[i] = temp > a[i] ? temp : a[i];}for(i = n - 2;i >= 0;i--){tl[i] = max > tl[i] ? max : tl[i];max = tl[i];}max = hd[0] + tl[1];for(i = 1;i < n - 1;i++){temp = hd[i] + tl[i + 1];max = max > temp ? max : temp;}printf("%d\n",max);}return 0;}4、最长公共子序列(不严格连续)#include <stdio.h>#include <string.h>#define MAXLEN 100void LCSLength(char *x, char *y, int m, int n, int c[][MAXLEN], int b[][MAXLEN]) {int i, j;for(i = 0; i <= m; i++)c[i][0] = 0;for(j = 1; j <= n; j++)c[0][j] = 0;for(i = 1; i<= m; i++){for(j = 1; j <= n; j++){if(x[i-1] == y[j-1]){c[i][j] = c[i-1][j-1] + 1;b[i][j] = 0;}else if(c[i-1][j] >= c[i][j-1]){c[i][j] = c[i-1][j];b[i][j] = 1;}else{c[i][j] = c[i][j-1];b[i][j] = -1;}}}}void PrintLCS(int b[][MAXLEN], char *x, int i, int j) {if(i == 0 || j == 0)return;if(b[i][j] == 0){PrintLCS(b, x, i-1, j-1);printf("%c ", x[i-1]);}else if(b[i][j] == 1)PrintLCS(b, x, i-1, j);elsePrintLCS(b, x, i, j-1);}int main(int argc, char **argv){char x[MAXLEN] = {"ABCBDAB"};char y[MAXLEN] = {"BDCABA"};int b[MAXLEN][MAXLEN];int c[MAXLEN][MAXLEN];int m, n;m = strlen(x);n = strlen(y);LCSLength(x, y, m, n, c, b);PrintLCS(b, x, m, n);return 0;}5、最长公共子序列(不严格连续)#include<iostream>#include<cstdio>#include<memory.h>using namespace std;const int N = 505;int num1[N],num2[N],f[N][N];int main(){int t,n,m;scanf("%d",&t);while(t--){scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&num1[i]);scanf("%d",&m);for(int j=1;j<=m;j++)scanf("%d",&num2[j]);memset(f,0,sizeof(f));int answer=0;int ma;for(int i=1;i<=n;i++){ma=0;for(int j=1;j<=m;j++){f[i][j]=f[i-1][j];if(num1[i]>num2[j]&&f[i-1][j]>ma)ma=f[i-1][j];if(num1[i]==num2[j])f[i][j]=ma+1;}}for(int j=0;j<=m;j++)answer=max(answer,f[n][j]);printf("%d\n",answer);if(t!=0)printf("\n");}return 0;}6、最大子矩阵和#include <iostream>#include<memory.h>using namespace std;//求最大连续子矩阵和,动态规划,O(n^3) of time:/*输入41 -4 3 -8-3 5 2 -32 -1 8 1-1 1 -2 -4输出14*/int max_sum(int n, int *arr){ //求单个序列的最大连续子串和int result=0;int b=0;for(int i=0;i<n;i++){if(b>0) b+=arr[i];else b=arr[i];if(b>result) result=b;}return result;}int max_sum2(int m, int n, int **arr){int result=0;int *b=new int[n];for(int i=0;i<m;i++){memset(b,0,sizeof(int)*n);for(int j=i;j<m;j++){for(int k=0;k<n;k++)b[k]+=arr[j][k];//b[k]=arr[i][k]+arr[i+1][k]+...+arr[j][k]//从例子来说,当i=1,j=2时,有b[k]=arr[1][k]+arr[2][k],这时取到maxint max=max_sum(n,b);if(max>result) result=max;}}delete b;return result;}int main(){int N;cin>>N;int i,j;int **arr=new int*[N];for(i=0;i<N;i++){arr[i]=new int[N];for(j=0;j<N;j++)cin>>arr[i][j];}cout<<max_sum2(N,N,arr)<<endl;for(i=0;i<N;i++)delete arr[i];delete arr;return 0;}7、石子合并问题#include <iostream>#include <stdio.h>using namespace std;//石头合并问题PKU 1086 动态规划/*输入:44 1 2 3输出:*/#define MAX 1000000000int a[202];//每个石头的重量long f[202][202];//f[i][j],第i个石头分到第j个石头合并的最小代价long sum[202][202];//sum[i][j],第i个石头到第j个石头的重量之和void print(int num){int i,j;for(i=1;i<=num;i++){for(j=1;j<=num;j++)printf("%3d",f[i][j]);cout<<endl;}cout<<endl;}void cal(int num){int i,j,k,min,d;for(i=1;i<=num;i++)f[i][i]=0;//不合并时的代价for(i=1;i<num;i++){sum[i][i]=a[i];for(j=i+1;j<=num;j++){sum[i][j]=sum[i][j-1]+a[j];}}sum[num][num]=a[num];for(d=1;d<=num-1;d++){for(i=1;i<=num-d;i++){j=i+d;min=MAX;//i..k为一堆石头,k+1,k+2...j为另一堆石头//f[i][j]为f[i][k]+f[k+1][j]+sum[i][j]的最小值(i<=j<k)for(k=i;k<j;k++)if(min>f[i][k]+f[k+1][j]+sum[i][j]) min=f[i][k]+f[k+1][j]+sum[i][j];f[i][j]=min;print(num);}}}int main(){int num,i;scanf("%d",&num);for(i=1;i<=num;i++)cin>>a[i];cal(num);cout<<f[1][num]<<endl;return 0;}8、最大乘积#include <iostream>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <math.h>using namespace std;//添加乘号得到最大乘积动态规划#define NMAX 12#define CMAX 7__int64 f[NMAX][CMAX];//f[i][j],长度为i,用了j个乘号后的最大值char str[22];void print(int num,int k){ //用于调试时打印f[][]int i,j;for(i=0;i<num;i++){for(j=1;j<=k;j++)printf("%6d",f[i][j]);cout<<endl;}cout<<endl;// system("pause");}int conv(int start,int num){ //在str[i]中,以start为起点,num为长度所表示的数字int sum,i;sum=0;for(i=1;i<=num;i++){sum*=10;sum+=str[start+i-1]-'0';}return sum;}void cal(int num,int chen){int i,j,temp,k;for(i=0;i<num;i++){ //初始化,不用乘号时的情况f[i][0]=conv(0,i+1);}for(j=1;j<=chen;j++){for(i=j;i<num;i++){temp=0;for(k=0;k<i;k++){//a1,a2,a3..an用j个乘号连接//看成是a1,a2...ak已经用j-1个乘号连接,//然后再与后面的ak+1,ak+2..an组成的数用1个乘号连接if(temp<f[k][j-1]*conv(k+1,i-k))temp=f[k][j-1]*conv(k+1,i-k);}f[i][j]=temp;//找到局部的最大乘积}// print(num,chen);}}int main(){int num,chen;//num为字符串长度while(scanf("%d%d",&num,&chen)!=EOF){scanf("%s",&str);cal(num,chen);printf("%I64d\n",f[num-1][chen]);}return 0;}。
ACM(五篇范例)
ACM(五篇范例)第一篇:ACMDijkstra 模板/*************************************** * About:有向图的Dijkstra算法实现 * Author:Tanky Woo * Blog:t=0;if(flag == 0){printf(“Non”);}else{for(int i=min;i<=max;++i){if(mark[i]==1 && arr[i]==0)cnt++;}}if(cnt==1)printf(“Yesn”);elseprintf(“Non”);}} return 0;搜索算法模板BFS:1.#include2.#include3.#include4.#includeing namespace std;6.const int maxn=100;7.bool vst[maxn][maxn];// 访问标记8.int dir[4][2]={0,1,0,-1,1,0,-1,0};// 方向向量9.10.struct State // BFS 队列中的状态数据结构 11.{ 12.int x,y;// 坐标位置13.int Step_Counter;// 搜索步数统计器14.};15.16.State a[maxn];17.18.boolCheckState(State s)// 约束条件检验19.{ 20.if(!vst[s.x][s.y] &&...)// 满足条件 1: 21.return 1;22.else // 约束条件冲突 23.return 0;24.} 25.26.void bfs(State st)27.{ 28.queue q;// BFS 队列29.State now,next;// 定义 2 个状态,当前和下一个30.st.Step_Counter=0;// 计数器清零 31.q.push(st);// 入队32.vst[st.x][st.y]=1;// 访问标记33.while(!q.empty())34.{ 35.now=q.front();// 取队首元素进行扩展36.if(now==G)// 出现目标态,此时为Step_Counter 的最小值,可以退出即可37.{ 38.......// 做相关处理39.return;40.} 41.for(int i=0;i<4;i++)42.{ 43.next.x=now.x+dir[i][0];// 按照规则生成下一个状态44.next.y=now.y+dir[i][1];45.next.Step_Counter=now.Step_Coun ter+1;// 计数器加1 46.if(CheckState(next))// 如果状态满足约束条件则入队 47.{ 48.q.push(next);49.vst[next.x][next.y]=1;//访问标记 50.} 51.} 52.q.pop();// 队首元素出队53.} 54.return;55.} 56.57.int main()58.{ 59.......60.return 0;61.}代码:胜利大逃亡Ignatius被魔王抓走了,有一天魔王出差去了,这可是Ignatius逃亡的好机会.魔王住在一个城堡里,城堡是一个A*B*C的立方体,可以被表示成A个B*C的矩阵,刚开始Ignatius被关在(0,0,0)的位置,离开城堡的门在(A-1,B-1,C-1)的位置,现在知道魔王将在T分钟后回到城堡,Ignatius每分钟能从一个坐标走到相邻的六个坐标中的其中一个.现在给你城堡的地图,请你计算出Ignatius能否在魔王回来前离开城堡(只要走到出口就算离开城堡,如果走到出口的时候魔王刚好回来也算逃亡成功),如果可以请输出需要多少分钟才能离开,如果不能则输出-1.Input 输入数据的第一行是一个正整数K,表明测试数据的数量.每组测试数据的第一行是四个正整数A,B,C和T(1<=A,B,C<=50,1<=T<=1000),它们分别代表城堡的大小和魔王回来的时间.然后是A块输入数据(先是第0块,然后是第1块,第2块......),每块输入数据有B行,每行有C个正整数,代表迷宫的布局,其中0代表路,1代表墙.(如果对输入描述不清楚,可以参考Sample Input中的迷宫描述,它表示的就是上图中的迷宫) 特别注意:本题的测试数据非常大,请使用scanf输入,我不能保证使用cin能不超时.在本OJ上请使用Visual C++提交.Output 对于每组测试数据,如果Ignatius能够在魔王回来前离开城堡,那么请输出他最少需要多少分钟,否则输出-1.Sample Input 1 3 3 4 20 0 1 1 1 0 0 1 1 0 1 1 1 1 1 1 1 1 0 0 1 0 1 1 1 0 0 0 0 0 1 1 0 0 1 1 0Sample Output 11代码:#include #include #include #include #includeusing namespace std;int tx[] = {0,1,-1,0,0,0,0};int ty[] = {0,0,0,1,-1,0,0};int tz[] = {0,0,0,0,0,1,-1};int arr[55][55][55];int known[55][55][55];// 访问标记int a,b,c,d;struct state{int x,y,z;// 所在的坐标int step_count;//统计搜索步数。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
ACM模板[王克纯2020年9月21日最大子串int maxSum(int * a,int n){int sum = a[0],b = 0;for(int i=0;i<n;++i){if(b>0) b += a[i];else b = a[i];if(b > sum) sum = b;}return sum;}int Kadane(const int array[], size_t length, unsigned int& left, unsigned int& right){unsigned int i, cur_left, cur_right;int cur_max, max;cur_max = max = left = right = cur_left = cur_right = 0;for(i = 0; i < length; ++i){cur_max += array[i];if(cur_max > 0){cur_right = i;if(max < cur_max){max = cur_max;left = cur_left;right = cur_right;}}else{cur_max = 0;cur_left = cur_right = i + 1;}}return max;} 快速幂void js(int &a,int &b,int num) {b=1;while(num){if(num&1) b*=a;num>>=1;a*=a;}}矩阵乘法struct mat{int n,m;//n行m列int data[MAX][MAX];};void mul(const mat& a,const mat& b,mat& c) //c=a*b{int i,j,k;if (a.m!=b.n); //报错c.n=a.n,c.m=b.m;for (i=0;i<c.n;i++){for (j=0;j<c.m;j++){for (c.data[i][j]=k=0;k<a.m;k++) {c.data[i][j]+=a.data[i][k]*b.dat a[k][j]%m;//m为余数}c.data[i][j]%=m;}}}Bit位操作(宏定义,内联函数,stl)} #define bitwrite(a,i,n)(n)?(a)[(i)/8]|=1<<(i)%8:(a)[(i)/8]&=~(1<<(i)%8)//数组a的第i位写入n;#define bitread(a,i)((a)[(i)/8]>>((i)%8))&1//读取数组a的第i位inline void write(int i,int n){n?a[i/8]|=1<<i%8:a[i/8]&=~(1<<i% 8);}inline int read(int i){return (a[i/8]>>(i%8))&1;}#include<bitset>bitset<MAX> b;错排公式为M(n)=n!(1/2!-1/3!+…..+(-1)^n/n!)M(n)=n!-n!/1!+n!/2!-n!/3!+…+(-1)^n*n!/n!=sigma(k=2~n) (-1)^k*n!/k!Dn=[n!/e+0.5]容斥原理M(n)=n![1/0!-1/1!+1/2!-1/3!+1/4! +..+(-1)^n/n!]二分模板LL findr(LL array, LL low, LL high,LL target){while(low <= high){LL mid = (low + high)/2;if (array[mid] > target) high = mid - 1;else if (array[mid] < target) low = mid + 1;else return mid;}return -1;复用代码#include<stdio.h>#include<stdlib.h>#include<string.h>#define MAX 10void print(mat t){printf("*****************\n") ;for(int i=0;i<t.n;i++){for(int j=0;j<t.m;j++){printf("%d",t.data[i][j]);}putchar('\n');}}一些常量和函数:最大Long long __int64 INF = ~(((__int64)0x1)<<63);ceil()向上取整(math.h)floor()向下取整c字符串处理函数1)提取子串--strstr函数原型:char* strstr(char*src,char*find)函数说明:从字符串src中寻找find第一次出现的位置(不比较结束符NULL)返回值:返回指向第一次出现find位置的指针,如果没有找到则返回NULL2)接尾连接--strcat函数原型:char* strcat(char*dest,char*src)函数说明:把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'3)部分连接--strncat函数原型:char* strncat(char*dest,char*src,int n);函数说明:把src所指字符串的前n个字符添加到dest结尾处(覆盖dest结尾处的’\0’)并添加’’\0’.返回值:返回指向dest的指针。
4)将字串逆向--strrev函数原型:char*strrev(char*src)函数说明:把字符串src的所有字符的顺序颠倒过来(不包括NULL)返回值:返回指向颠倒顺序后的字符串指针C++字符串处理函数<string>string str;1. 字符串长度len = str.length();len = str.size();2. 字符串比较可以直接比较也可以:pare(str2);pare(pos1,len1,str2,pos2,len2); 值为负,0 ,正。
nops 长度到完。
3. 附加str1 += str2;或str1.append(str2);str1.append(str2.pos2,len2);4. 字符串提取str2 = str1.substr();str2 = str1.substr(pos1);str2 = str1.substr(pos1,len1);5. 字符串搜索where = str1.find(str2);where = str1.find(str2,pos1); pos1是从str1的第几位开始。
where = str1.rfind(str2); 从后往前搜。
6. 插入字符串不是赋值语句。
str1.insert(pos1,str2);str1.insert(pos1,str2,pos2,len2);str1.insert(pos1,numchar,char); numchar是插入次数,char 是要插入的字符。
7. 替换字符串str1.replace(pos1,str2);str1.replace(pos1,str2,pos2,len2);8. 删除字符串str.erase(pos,len)str.clear();9. 交换字符串swap(str1,str2);10. C --> C++char *cstr = "Hello";string str1;cstr = cstr;string str2(cstr);数学相关:PICK的定理:三角形面积s 三角形内部点n 三角形边上的点wn + w/2 - 1 = s欧几里德辗转相除法gcd(a, b) = gcd(b, a mod b)int gcd(int a, int b){int temp;while (b != 0){temp = b;b = a % b;a = temp;}return a;}PS: 最小公倍数= a * b / gcd(a, b)扩展欧几里得方程ax + by = C的(x)最小正整数解#include <stdio.h>#include <stdlib.h>int x,y,a,b;int extended_gcd(int a, int b){if (b == 0){x = 1; y = 0;return a;}else{int r = extended_gcd(b, a % b);int temp;temp = x;x = y;y = temp - a / b * y;return r;}}int main(){int i,j,m,s,c;scanf("%d%d%d", &a, &b, &c);m = extended_gcd(a,b);if (c%m!=0) {printf("error"); return 0;}x = x*(c/m);s = b/m;x = (x%s + s)%s;y = (c-x*a)/b;printf("%d %d\n", x,y);printf("gcd = %d\n", m);system("pause");}素数筛子a = 0 为素数#include <stdio.h>#include <string.h>#include <stdlib.h>#define MAX 10000int a[MAX];void odd(){int i,j;memset(a,0,sizeof(a));for (i=2;i<=MAX;i++){if (!a[i])for (j=2;j*i<=MAX;j++){a[i*j] = 1;}}}除数非互质的模线性方程//此算法可能输出0,注意细节特判,方程数为1,0时需要特判#include <stdio.h>#include <string.h>#include <stdlib.h>__int64 exgcd(__int64 a,__int64 b,__int64 &x,__int64 &y) {if(b==0){x=1,y=0;return a;}__int64 r=exgcd(b,a%b,x,y);__int64 t=x;x=y;y=t-a/b*y;return r;}int main(){__int64 flag=1,ans,x,y;//flag是否有解,ans存解得值int num;//num 方程数目scanf("%d",&num);num--;__int64 a,r;scanf("%I64d",&a);//a第一个除数scanf("%I64d",&r);//r第一个余数while(num--){__int64 b,_r;scanf("%I64d",&b);//b 除数scanf("%I64d",&_r);//_r 余数__int64 t=_r-r;__int64 d=exgcd(a,b,x,y);if(t%d) flag=0;__int64 temp=b/d;x*=t/d;x=(x%temp+temp)%temp;__int64 lcm=a*b/d;ans=a*x+r;ans=(ans%lcm+lcm)%lcm;a=lcm,r=ans;}if (flag) printf("%I64d\n",ans);else printf("No answer\n");//system("pause");}求解模线性方程组(中国余数定理)//b[0],b[1],b[2]….必须互质int ext_gcd(int a,int b,int& x,int& y){int t,ret;if (!b){x=1,y=0;return a;}ret=ext_gcd(b,a%b,x,y);t=x,x=y,y=t-a/b*y;return ret;}// x = b[0] (mod w[0])// x = b[1] (mod w[1])// ...// x = b[k-1] (mod w[k-1])//要求w[i]>0,w[i]与w[j]互质,解的范围1..n,n=w[0]*w[1]*...*w[k-1] int modular_linear_system(int b[],int w[],int k){int d,x,y,a=0,m,n=1,i;for (i=0;i<k;i++)n*=w[i];for (i=0;i<k;i++){m=n/w[i];d=ext_gcd(w[i],m,x,y);a=(a+y*m*b[i])%n;}return (a+n)%n;}生成法雷序列#include <cstdio>#include <string>#include <algorithm>using namespace std;const int MAX = 4000000;int total;int n,k;int farey[2][MAX];void make_farey_seq(int x1,int y1,int x2, int y2) {if(x1+x2 > n || y1+y2 > n) return;make_farey_seq(x1, y1,x1+x2, y1+y2);total ++;farey[0][total] = x1+x2;farey[1][total] = y1+y2;make_farey_seq(x1+x2, y1+y2,x2,y2);}int main(){int t;total = 1;farey[0][1] = 0;farey[1][1] = 1;n = 4;//n表示阶数make_farey_seq(0,1,1,1);farey[0][total+1] = 1;farey[1][total+1] = 1;while (1){scanf("%d",&t);printf("%d/%d\n",farey[0][t],farey[1][t]);}}欧拉函数int gcd(int a,int b){return b?gcd(b,a%b):a;}inline int lcm(int a,int b){return a/gcd(a,b)*b;}//求1..n-1中与n互质的数的个数int eular(int n){int ret=1,i;for (i=2;i*i<=n;i++)if (n%i==0){n/=i,ret*=i-1;while (n%i==0)n/=i,ret*=i;}if (n>1)ret*=n-1;return ret;}费马小定理•费马小定理➢设a是正整数,p是素数,且a和p互素➢则a p-1≡1 (mod p)欧拉定理➢a和n都是正整数,且a和n互素➢aΦ(n)≡1 (mod n)幂模➢a b (mod n) = a(b % Φ(n) + Φ(n)) (mod n)➢n是任意正整数,a和b是任意整数,且b不小于Φ(n) 多项式求根(牛顿法)/* 牛顿法解多项式的根输入:多项式系数c[],多项式度数n,求在[a,b]间的根输出:根要求保证[a,b]间有根*/double fabs( double x ){return (x<0)? -x : x;}double f(int m, double c[], double x){int i;double p = c[m];for (i=m; i>0; i--)p = p*x + c[i-1];return p;}int newton(double x0, double *r,double c[], double cp[], int n,double a, double b, double eps){int MAX_ITERATION = 1000;int i = 1;double x1, x2, fp, eps2 = eps/10.0;x1 = x0;while (i < MAX_ITERATION) {x2 = f(n, c, x1);fp = f(n-1, cp, x1);if ((fabs(fp)<0.000000001) && (fabs(x2)>1.0))return 0;x2 = x1 - x2/fp;if (fabs(x1-x2)<eps2) {if (x2<a || x2>b)return 0;*r = x2;return 1;}x1 = x2;i++;}return 0;}double Polynomial_Root(double c[], int n, double a, double b, double eps){double *cp;int i;double root;cp = (double *)calloc(n, sizeof(double));for (i=n-1; i>=0; i--) {cp[i] = (i+1)*c[i+1];}if (a>b) {root = a; a = b; b = root;}if ((!newton(a, &root, c, cp, n, a, b, eps)) &&(!newton(b, &root, c, cp, n, a, b, eps)))newton((a+b)*0.5, &root, c, cp, n, a, b, eps);free(cp);if (fabs(root)<eps)return fabs(root);elsereturn root;}用位运算生成所有组合情况例如生成int a[4] = {1,2,8,10}中任意取数的和的情况共2^4 = 16中情况可以这写代码:#include <stdio.h>#include <stdlib.h>#include <string.h>int main(){int i,k1,j,t;int a[4] = {1,2,8,10},ans[16];memset(ans,0,sizeof(ans));k1 = 4;t = 0;for(i=0;i<(1<<k1);i++)for(j=0;j<k1;j++)if(i&(1<<j))ans[i] += a[j];for (i=0;i<(1<<k1);i++)printf("%d ",ans[i]);system("pause");} 矩阵加速//p*q矩阵n次幂#define p 2#define q 2void multi(int a[][q],int b[][q],int c[][q])//矩阵a*b结果保存在c中{int ans[p][q] = {0};int i,j,k;for (i=0;i<p;i++){for (j=0;j<q;j++){for (k=0;k<p;k++)ans[i][j] += a[i][k]*b[k][j];}}for (i=0;i<p;i++)for (j=0;j<q;j++)c[i][j] = ans[i][j];}void ppow(int b[p][q], int n,int c[p][q]){int test;while(n>1){test = n%2;if(test==0){multi(b,b,b);n = n/2;}else{multi(c,b,c);n = n-1;}}multi(c,b,c);}调用ppow(b,n,c); b矩阵的n次幂初始化b为原矩阵c为单位矩阵结果保存在c中,每次使用都要初始化b和c矩阵加速带mod#define p 2#define q 2#define mod 10000__int64 c[2][2],n;__int64 a[2][2] = {{1,1},{1,0}};void init(__int64 c[][q]){int i,j;for (i=0;i<p;i++)for (j=0;j<q;j++)if (i==j) c[i][j] = 1;else c[i][j] = 0;}void multi(__int64 a[][q],__int64 b[][q],__int64 c[][q])//矩阵a*b结果保存在c中{__int64 ans[p][q] = {0};int i,j,k;for (i=0;i<p;i++){for (j=0;j<q;j++){for (k=0;k<p;k++){ans[i][j] += (a[i][k]*b[k][j])%mod;ans[i][j]%=mod;}ans[i][j]%=mod;if (ans[i][j]==0) ans[i][j] = mod;}}for (i=0;i<p;i++)for (j=0;j<q;j++)c[i][j] = ans[i][j];}void ppow(__int64 b[p][q], __int64 n,__int64 c[p][q]){int test;while(n>1){test = n%2;if(test==0){multi(b,b,b);n = n/2;}else{multi(c,b,c);n = n-1;}}multi(c,b,c);}//矩阵中的数》=mod 不为0故最后矩阵所有数要%mod矩阵快速幂(结构体实现)并求连续矩阵和#include<stdio.h>typedef struct node{int matrix[32][32];}Matrix;Matrix data,unit;int n,k,m;Matrix add(Matrix a,Matrix b){Matrix c;int i,j;for(i=0;i<n;i++)for(j=0;j<n;j++){c.matrix[i][j]=a.matrix[i][j]+b.matrix[i][j];c.matrix[i][j]%=m;}return c;}Matrix mul(Matrix a,Matrix b){Matrix c;int i,j,l;for(i=0;i<n;i++)for(j=0;j<n;j++){c.matrix[i][j]=0;for(l=0;l<n;l++){c.matrix[i][j]+=a.matrix[i][l]*b.matrix[l][j];c.matrix[i][j]%=m;}}return c;}Matrix power(int t){Matrix p,q;q=data;p=unit;while(t!=1){if(t&1){t--;p=mul(p,q);}else{t>>=1;q=mul(q,q);}}p=mul(p,q);return p;}Matrix mulSum(int k)//求连续n次幂和{if(k==1) return data;Matrix temp1,temp2;temp1=mulSum(k/2);if(k&1){temp2=power(k/2+1);temp1=add(temp1,mul(temp1,temp2));temp1=add(temp2,temp1);}else{temp2=power(k/2);temp1=add(temp1,mul(temp1,temp2));}return temp1;}Matrix mulSum(int k) 求奇数次幂和k为真实个数如1+3+5次和k=3{//if(k==2) return add(data,power(2));if(k==1) return data;Matrix temp1,temp2;temp1=mulSum(k/2);if(k&1){temp2=power((k/2+1)*2-1);temp1=add(temp1,mul(mul(temp1,temp2),data));temp1=add(temp2,temp1);}else{temp2=power(k);temp1=add(temp1,mul(temp1,temp2));}return temp1;}int main(){int t;Matrix r;scanf("%d %d %d",&n,&k,&m);int i,j;for(i=0;i<n;i++)for(j=0;j<n;j++){scanf("%d",&data.matrix[i][j]);unit.matrix[i][j]=(i==j);}r=mulSum(k);int sum=0;for(i=0;i<n;i++){for(j=0;j<n-1;j++)printf("%d ",r.matrix[i][j]%m);printf("%d\n",r.matrix[i][n-1]%m);}return 0;}朴素快速幂__int64 pow(__int64 a,__int64 b){__int64 t;if (b==0) return 1;if (b==1) return a;if (b%2==0){t = pow(a,b/2);return t*t;}else{return a*pow(a,b-1);}}快速幂带模__int64 mod;__int64 pow(__int64 a,__int64 b){__int64 t;if (b==0) return 1;if (b==1) return a%mod;if (b%2==0){t = pow(a,b/2)%mod;if (t==0) t = mod;t = (t*t)%mod;//if (t==0) t = mod;return t;}else{t = pow(a,b-1)%mod;//if (t==0) t = mod;t = (t*a)%mod;if (t==0) t = mod;return t;}}快速a的n次方除以b 模m__int64 mod;// a / b (mod n) = a % (b * n) / b (mod n)__int64 pow(__int64 a,__int64 b){__int64 t;if (b==0) return 1;if (b==1) return a%mod;if (b%2==0){t = pow(a,b/2)%mod;if (t==0) t = mod;t = (t*t)%mod;if (t==0) t = mod;return t;}else{t = pow(a,b-1)%mod;if (t==0) t = mod;t = (t*a)%mod;if (t==0) t = mod;return t;}}__int64 mpow(__int64 a,__int64 n,__int64 b,__int64 m)//a的n次方除以b 模m{mod = m*b;__int64 ans;ans = pow(a,n);//ans += 3;ans%=mod;ans /= b%m;}计算几何:平面欧拉公式国家数为F,边数为E,顶点数为VV+F-E=1(F≧2)立体欧拉公式V是多面体P的顶点个数,F是多面体P的面数,E是多面体P的棱的条数V+F-E=2几何公式【三角形】:1. 半周长P=(a+b+c)/22. 面积S=aHa/2=absin(C)/2=sqrt(P(P-a)(P-b)(P-c))3. 中线Ma=sqrt(2(b^2+c^2)-a^2)/2=sqrt(b^2+c^2+2bccos(A))/24. 角平分线Ta=sqrt(bc((b+c)^2-a^2))/(b+c)=2bccos(A/2)/(b+c)5. 高线Ha=bsin(C)=csin(B)=sqrt(b^2-((a^2+b^2-c^2)/(2a))^2)6. 内切圆半径r=S/P=asin(B/2)sin(C/2)/sin((B+C)/2)=4Rsin(A/2)sin(B/2)sin(C/2)=sqrt((P-a)(P-b)(P-c)/P)=Ptan(A/2)tan(B/2)tan(C/2)7. 外接圆半径R=abc/(4S)=a/(2sin(A))=b/(2sin(B))=c/(2sin(C)) 【四边形】:D1,D2为对角线,M对角线中点连线,A为对角线夹角1. a^2+b^2+c^2+d^2=D1^2+D2^2+4M^22. S=D1D2sin(A)/2(以下对圆的内接四边形)3. ac+bd=D1D24. S=sqrt((P-a)(P-b)(P-c)(P-d)),P为半周长【正n边形】:R为外接圆半径,r为内切圆半径1. 中心角A=2PI/n2. 内角C=(n-2)PI/n3. 边长a=2sqrt(R^2-r^2)=2Rsin(A/2)=2rtan(A/2)4. 面积S=nar/2=nr^2tan(A/2)=nR^2sin(A)/2=na^2/(4tan(A/2)) 【圆】:1. 弧长L=rA2. 弦长a=2sqrt(2hr-h^2)=2rsin(A/2)3. 弓形高h=r-sqrt(r^2-a^2/4)=r(1-cos(A/2))=atan(A/4)/24. 扇形面积S1=rl/2=r^2A/25. 弓形面积S2=(rl-a(r-h))/2=r^2(A-sin(A))/2【棱柱】:1. 体积V=Ah,A为底面积,h为高2. 侧面积S=lp,l为棱长,p为直截面周长3. 全面积T=S+2A【棱锥】: 1. 体积V=Ah/3,A为底面积,h为高(以下对正棱锥)2. 侧面积S=lp/2,l为斜高,p为底面周长3. 全面积T=S+A【棱台】:1. 体积V=(A1+A2+sqrt(A1A2))h/3,A1.A2为上下底面积,h为高(以下为正棱台)2. 侧面积S=(p1+p2)L/2,p1.p2为上下底面周长,l为斜高3. 全面积T=S+A1+A2【圆柱】:1. 侧面积S=2PIrh2. 全面积T=2PIr(h+r)3. 体积V=PIr^2h【圆锥】:1. 母线L=sqrt(h^2+r^2)2. 侧面积S=PIrl3. 全面积T=PIr(L+r)4. 体积V=PIr^2h/3【圆台】:1. 母线L=sqrt(h^2+(r1-r2)^2)2. 侧面积S=PI(r1+r2)L3. 全面积T=PIr1(L+r1)+PIr2(L+r2)4. 体积V=PI(r1^2+r2^2+r1r2)h/3【球】:1. 全面积T=4PIr^22. 体积V=4PIr^3/3【球台】:1. 侧面积S=2PIrh2. 全面积T=PI(2rh+r1^2+r2^2)3. 体积V=PIh(3(r1^2+r2^2)+h^2)/6【球扇形】:1. 全面积T=PIr(2h+r0),h为球冠高,r0为球冠底面半径2. 体积V=2PIr^2h/3确定连续线段是向左转还是向右转struct point{double x, y;};//计算p3相对于p1p2的转向(p1p3 相对于p1p2)//返回>0 逆时针,<0顺时针(p1p3相对于p1p2)double direction(point p1, point p2, point p3){return (p3.x - p1.x) * (p2.y - p1.y) - (p2.x - p1.x) * (p3.y - p1.y);}判断线段相交,共端点也算bool online(node p1, node p2, node p3){return (p3.x >= min(p1.x, p2.x) && p3.x <= max(p1.x, p2.x)&& p3.y >= min(p1.y,p2.y) && p3.y <= max(p1.y, p2.y));}bool insect(node p1, node p2, node p3, node p4){double d1 = direction(p3, p4, p1);double d2 = direction(p3, p4, p2);double d3 = direction(p1, p2, p3);double d4 = direction(p1, p2, p4);if (d1 * d2 < 0 && d3 * d4 < 0) return true;else if (d1 == 0 && online(p3, p4, p1)) return true;//共点的情况else if (d2 == 0 && online(p3, p4, p2)) return true;else if (d3 == 0 && online(p1, p2, p3)) return true;else if (d4 == 0 && online(p1, p2, p4)) return true;return false;}判断线段和直线相交(p1,p2是线段的两个端点,p3,p4为直线上不相同的两点)bool insect(node p1, node p2, node p3, node p4){double d1 = direction(p3, p4, p1);double d2 = direction(p3, p4, p2);return (d1 * d2 < 0 || d1 == 0 || d2 == 0);}Graham扫描法求凸包#include <stdio.h>#include <algorithm>using namespace std;int max(int a,int b){return a>b?a:b;}int min(int a,int b){return a>b?b:a;}struct node{int x;int y;};struct node x[10010];int ans[10010], cnt,n;//cnt记录凸包元素个数,实际个数bool cmp(node p1, node p2){int temp = (p1.x - x[0].x) * (p2.y - x[0].y) - (p2.x - x[0].x) * (p1.y - x[0].y);if (temp == 0) return (p1.x >= min(x[0].x, p2.x) && p1.x <= max(x[0].x, p2.x));else return temp > 0;}bool CrossLeft(node p1, node p2, node p3)//p3是否严格左转,共线不算左转这样是点最少的凸包,共线点只算一个{return ((p3.x - p1.x) * (p2.y - p1.y) - (p2.x - p1.x) * (p3.y - p1.y)) < 0;}void Graham(){sort(x + 1, x + n, cmp);cnt = 0; // 以第一个点为基准,逆时针排序ans[cnt++] = 0;ans[cnt++] = 1;for(int i = 2; i < n; i++){while(cnt > 1 && !CrossLeft(x[ans[cnt - 2]], x[ans[cnt - 1]], x[i])) cnt--;ans[cnt++] = i;}ans[cnt++] = 0;cnt--;}读入的时候从0开始读点,最小点(优先y最小,其次x最小)交换到x[0]处点的标号保存在ans里,共cnt个,从0——cnt-1Ans的标号是排过序以后的不与输入的编号对应叉积判断直线相交情况,求交点这里也用到叉积的原理。