ACM程序设计大赛常用算法模板
- 格式:docx
- 大小:253.18 KB
- 文档页数:124
三角形面积计算 (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个元素。
目录一、图论 (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模板[王克纯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的指针。
/*计算几何目录㈠点的基本运算1. 平面上两点之间距离12. 判断两点是否重合13. 矢量叉乘14. 矢量点乘25. 判断点是否在线段上26. 求一点饶某点旋转后的坐标27. 求矢量夹角2㈡线段及直线的基本运算1. 点与线段的关系32. 求点到线段所在直线垂线的垂足43. 点到线段的最近点44. 点到线段所在直线的距离45. 点到折线集的最近距离46. 判断圆是否在多边形内57. 求矢量夹角余弦58. 求线段之间的夹角59. 判断线段是否相交610.判断线段是否相交但不交在端点处611.求线段所在直线的方程612.求直线的斜率713.求直线的倾斜角714.求点关于某直线的对称点715.判断两条直线是否相交及求直线交点716.判断线段是否相交,如果相交返回交点7㈢多边形常用算法模块1. 判断多边形是否简单多边形82. 检查多边形顶点的凸凹性93. 判断多边形是否凸多边形94. 求多边形面积95. 判断多边形顶点的排列方向,方法一106. 判断多边形顶点的排列方向,方法二107. 射线法判断点是否在多边形内108. 判断点是否在凸多边形内119. 寻找点集的graham算法1210.寻找点集凸包的卷包裹法1311.判断线段是否在多边形内1412.求简单多边形的重心1513.求凸多边形的重心1714.求肯定在给定多边形内的一个点1715.求从多边形外一点出发到该多边形的切线1816.判断多边形的核是否存在19㈣圆的基本运算1 .点是否在圆内202 .求不共线的三点所确定的圆21㈤矩形的基本运算1.已知矩形三点坐标,求第4点坐标22㈥常用算法的描述22㈦补充1.两圆关系:242.判断圆是否在矩形内:243.点到平面的距离:254.点是否在直线同侧:255.镜面反射线:256.矩形包含:267.两圆交点:278.两圆公共面积:289. 圆和直线关系:2910. 内切圆:3011. 求切点:3112. 线段的左右旋:3113.公式:32*//* 需要包含的头文件*/#include <cmath >/* 常用的常量定义*/const double INF = 1E200const double EP = 1E-10const int MAXV = 300const double PI = 3.14159265/* 基本几何结构*/struct POINT{double x;double y;POINT(double a=0, double b=0) { x=a; y=b;} //constructor};struct LINESEG{POINT s;POINT e;LINESEG(POINT a, POINT b) { s=a; e=b;}LINESEG() { }};struct LINE // 直线的解析方程a*x+b*y+c=0 为统一表示,约定a >= 0{double a;double b;double c;LINE(double d1=1, double d2=-1, double d3=0) {a=d1; b=d2; c=d3;}};/*********************** ** 点的基本运算** ***********************/double dist(POINT p1,POINT p2) // 返回两点之间欧氏距离{return( sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y) ) );}bool equal_point(POINT p1,POINT p2) // 判断两个点是否重合{return ( (abs(p1.x-p2.x)<EP)&&(abs(p1.y-p2.y)<EP) );}/****************************************************************************** r=multiply(sp,ep,op),得到(sp-op)和(ep-op)的叉积r>0:ep在矢量opsp的逆时针方向;r=0:opspep三点共线;r<0:ep在矢量opsp的顺时针方向******************************************************************************* /double multiply(POINT sp,POINT ep,POINT op){return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y));}/*r=dotmultiply(p1,p2,op),得到矢量(p1-op)和(p2-op)的点积,如果两个矢量都非零矢量r<0:两矢量夹角为锐角;r=0:两矢量夹角为直角;r>0:两矢量夹角为钝角******************************************************************************* /double dotmultiply(POINT p1,POINT p2,POINT p0){return ((p1.x-p0.x)*(p2.x-p0.x)+(p1.y-p0.y)*(p2.y-p0.y));}/****************************************************************************** 判断点p是否在线段l上条件:(p在线段l所在的直线上) && (点p在以线段l为对角线的矩形内)******************************************************************************* /bool online(LINESEG l,POINT p){return( (multiply(l.e,p,l.s)==0) &&( ( (p.x-l.s.x)*(p.x-l.e.x)<=0 )&&( (p.y-l.s.y)*(p.y-l.e.y)<=0 ) ) ); }// 返回点p以点o为圆心逆时针旋转alpha(单位:弧度)后所在的位置POINT rotate(POINT o,double alpha,POINT p){POINT tp;p.x-=o.x;p.y-=o.y;tp.x=p.x*cos(alpha)-p.y*sin(alpha)+o.x;tp.y=p.y*cos(alpha)+p.x*sin(alpha)+o.y;return tp;}/* 返回顶角在o点,起始边为os,终止边为oe的夹角(单位:弧度)角度小于pi,返回正值角度大于pi,返回负值可以用于求线段之间的夹角原理:r = dotmultiply(s,e,o) / (dist(o,s)*dist(o,e))r'= multiply(s,e,o)r >= 1 angle = 0;r <= -1 angle = -PI-1<r<1 && r'>0 angle = arccos(r)-1<r<1 && r'<=0 angle = -arccos(r)*/double angle(POINT o,POINT s,POINT e){double cosfi,fi,norm;double dsx = s.x - o.x;double dsy = s.y - o.y;double dex = e.x - o.x;double dey = e.y - o.y;cosfi=dsx*dex+dsy*dey;norm=(dsx*dsx+dsy*dsy)*(dex*dex+dey*dey);cosfi /= sqrt( norm );if (cosfi >= 1.0 ) return 0;if (cosfi <= -1.0 ) return -3.1415926;fi=acos(cosfi);if (dsx*dey-dsy*dex>0) return fi; // 说明矢量os 在矢量oe的顺时针方向return -fi;}/*****************************\* ** 线段及直线的基本运算** *\*****************************//* 判断点与线段的关系,用途很广泛本函数是根据下面的公式写的,P是点C到线段AB所在直线的垂足AC dot ABr = ---------||AB||^2(Cx-Ax)(Bx-Ax) + (Cy-Ay)(By-Ay)= -------------------------------L^2r has the following meaning:r=0 P = Ar=1 P = Br<0 P is on the backward extension of ABr>1 P is on the forward extension of AB0<r<1 P is interior to AB*/double relation(POINT p,LINESEG l){LINESEG tl;tl.s=l.s;tl.e=p;return dotmultiply(tl.e,l.e,l.s)/(dist(l.s,l.e)*dist(l.s,l.e));}// 求点C到线段AB所在直线的垂足PPOINT perpendicular(POINT p,LINESEG l){double r=relation(p,l);POINT tp;tp.x=l.s.x+r*(l.e.x-l.s.x);tp.y=l.s.y+r*(l.e.y-l.s.y);return tp;}/* 求点p到线段l的最短距离,并返回线段上距该点最近的点np注意:np是线段l上到点p最近的点,不一定是垂足*/double ptolinesegdist(POINT p,LINESEG l,POINT &np){double r=relation(p,l);if(r<0){np=l.s;return dist(p,l.s);}if(r>1){np=l.e;return dist(p,l.e);}np=perpendicular(p,l);return dist(p,np);}// 求点p到线段l所在直线的距离,请注意本函数与上个函数的区别double ptoldist(POINT p,LINESEG l){return abs(multiply(p,l.e,l.s))/dist(l.s,l.e);}/* 计算点到折线集的最近距离,并返回最近点.注意:调用的是ptolineseg()函数*/double ptopointset(int vcount,POINT pointset[],POINT p,POINT &q) {int i;double cd=double(INF),td;LINESEG l;POINT tq,cq;for(i=0;i<vcount-1;i++)l.s=pointset[i];l.e=pointset[i+1];td=ptolinesegdist(p,l,tq);if(td<cd){cd=td;cq=tq;}}q=cq;return cd;}/* 判断圆是否在多边形内.ptolineseg()函数的应用2 */bool CircleInsidePolygon(int vcount,POINT center,double radius,POINT polygon[]){POINT q;double d;q.x=0;q.y=0;d=ptopointset(vcount,polygon,center,q);if(d<radius||fabs(d-radius)<EP)return true;elsereturn false;}/* 返回两个矢量l1和l2的夹角的余弦(-1 --- 1)注意:如果想从余弦求夹角的话,注意反余弦函数的定义域是从0到pi */double cosine(LINESEG l1,LINESEG l2){return (((l1.e.x-l1.s.x)*(l2.e.x-l2.s.x) +(l1.e.y-l1.s.y)*(l2.e.y-l2.s.y))/(dist(l1.e,l1.s)*dist(l2.e,l2.s))) );}// 返回线段l1与l2之间的夹角单位:弧度范围(-pi,pi)double lsangle(LINESEG l1,LINESEG l2){POINT o,s,e;o.x=o.y=0;s.x=l1.e.x-l1.s.x;s.y=l1.e.y-l1.s.y;e.x=l2.e.x-l2.s.x;e.y=l2.e.y-l2.s.y;return angle(o,s,e);// 如果线段u和v相交(包括相交在端点处)时,返回true////判断P1P2跨立Q1Q2的依据是:( P1 - Q1 ) ×( Q2 - Q1 ) * ( Q2 - Q1 ) ×( P2 - Q1 ) >= 0。
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}}}。
专用模板目录:一、图论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模板一、贪心算法 (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,大家都懂得。
目录一、数学问题 (4)1.精度计算——大数阶乘 (4)2.精度计算——乘法(大数乘小数) (4)3.精度计算——乘法(大数乘大数) (5)4.精度计算——加法 (6)5.精度计算——减法 (7)6.任意进制转换 (8)7.最大公约数、最小公倍数 (9)8.组合序列 (10)9.快速傅立叶变换(FFT) (10)10.Ronberg 算法计算积分 (12)11.行列式计算 (14)12.求排列组合数 (15)13.求某一天星期几 (15)14.卡特兰(Catalan) 数列原理 (16)15.杨辉三角 (16)16.全排列 (17)17.匈牙利算法----最大匹配问题 (18)18.最佳匹配KM 算法 (20)二、字符串处理 (22)1.字符串替换 (22)2.字符串查找 (23)3.字符串截取 (24)4.LCS-最大公共子串长度 (24)5.LCS-最大公共子串长度 (25)6.数字转换为字符 (26)三、计算几何 (27)1.叉乘法求任意多边形面积 (27)2.求三角形面积 (27)3.两矢量间角度 (28)4.两点距离(2D、3D) (28)5.射向法判断点是否在多边形内部 (29)6.判断点是否在线段上 (30)7.判断两线段是否相交 (31)8.判断线段与直线是否相交 (32)9.点到线段最短距离 (32)10.求两直线的交点 (33)11.判断一个封闭图形是凹集还是凸集 (34)12.Graham 扫描法寻找凸包 (35)13.求两条线段的交点 (36)四、数论 (37)1.x 的二进制长度 (37)2.返回x 的二进制表示中从低到高的第i 位 (38)3.模取幂运算 (38)4.求解模线性方程 (39)5.求解模线性方程组(中国余数定理) (39)6.筛法素数产生器 (40)7.判断一个数是否素数 (41)8.求距阵最大和 (42)8.求一个数每一位相加之和 (43)10.质因数分解 (43)11.高斯消元法解线性方程组 (44)五、图论 (45)1.Prim 算法求最小生成树................................................. 45 2.Dijkstra 算法求单源最短路径.. (46)3.Bellman-ford 算法求单源最短路径 (47)4.Floyd-Warshall 算法求每对节点间最短路径 (48)5.解欧拉图 (49)六、排序/查找 (50)1.快速排序 (50)2.希尔排序 (51)3.选择法排序 (52)4.二分查找 (52)七、数据结构 (53)1.顺序队列 (53)2.顺序栈 (56)3.链表 (59)4.链栈 (63)5.二叉树 (66)八、高精度运算专题 (68)1.专题函数说明 (68)2.高精度数比较 (69)3.高精度数加法 (69)4.高精度数减法 (70)5.高精度乘10 (71)6.高精度乘单精度 (71)7.高精度乘高精度 (72)8.高精度除单精度 (72)9.高精度除高精度 (73)九、标准模板库的使用 (74)1.计算求和 (74)2.求数组中的最大值 (76)3. sort 和qsort (76)十、其他 (78)1.运行时间计算 (78)DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD一、数学问题1.精度计算——大数阶乘语法:int result=factorial(int n);参数:n:n 的阶乘返回值:阶乘结果的位数注意:本程序直接输出n!的结果,需要返回结果请保留long a[] 需要math.h源程序: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;}if(c>0) {m++;a[m]=c;}}w=m*4+log10(a[m])+1;printf("\n%ld",a[m]);for(i=m-1;i>=0;i--) printf("%4.4ld",a[i]);return w;}我也可以做到..5 / 782.精度计算——乘法(大数乘小数)语法:mult(char c[],char t[],int m);参数:c[]:被乘数,用字符串表示,位数不限t[]:结果,用字符串表示m:乘数,限定10 以内返回值:null注意:需要string.h源程序:void mult(char c[],char t[],int m){int i,l,k,flag,add=0;char s[100];l=strlen(c);for (i=0;i<l;i++)s[l-i-1]=c[i]-'0';for (i=0;i<l;i++){k=s[i]*m+add;if (k>=10) {s[i]=k%10;add=k/10;flag=1;} else{s[i]=k;flag=0;add=0;}}if (flag) {l=i+1;s[i]=add;} else l=i;for (i=0;i<l;i++)t[l-1-i]=s[i]+'0'; t[l]='\0';}3.精度计算——乘法(大数乘大数)语法:mult(char a[],char b[],char s[]);参数:a[]:被乘数,用字符串表示,位数不限b[]:乘数,用字符串表示,位数不限t[]:结果,用字符串表示返回值:null注意:空间复杂度为o(n^2)需要string.h源程序:void mult(char a[],char b[],char s[]){我也可以做到..6 / 78int i,j,k=0,alen,blen,sum=0,res[65][65]={0},flag=0; char result[65];alen=strlen(a);blen=strlen(b);for (i=0;i<alen;i++)for (j=0;j<blen;j++) res[i][j]=(a[i]-'0')*(b[j]-'0');for (i=alen-1;i>=0;i--){for (j=blen-1;j>=0;j--) sum=sum+res[i+blen-j-1][j]; result[k]=sum%10;k=k+1;sum=sum/10;}for (i=blen-2;i>=0;i--){for (j=0;j<=i;j++) sum=sum+res[i-j][j];result[k]=sum%10;k=k+1;sum=sum/10;}if (sum!=0) {result[k]=sum;k=k+1;}for (i=0;i<k;i++) result[i]+='0';for (i=k-1;i>=0;i--) s[i]=result[k-1-i];s[k]='\0';while(1){if (strlen(s)!=strlen(a)&&s[0]=='0')strcpy(s,s+1);elsebreak;}}4.精度计算——加法语法:add(char a[],char b[],char s[]);参数:a[]:被加数,用字符串表示,位数不限b[]:加数,用字符串表示,位数不限s[]:结果,用字符串表示返回值:null注意:空间复杂度为o(n^2)我也可以做到..7 / 78需要string.hDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD源程序:void add(char a[],char b[],char back[]){int i,j,k,up,x,y,z,l;char *c;if (strlen(a)>strlen(b)) l=strlen(a)+2; else l=strlen(b)+2; c=(char *) malloc(l*sizeof(char));i=strlen(a)-1;j=strlen(b)-1;k=0;up=0;while(i>=0||j>=0){if(i<0) x='0'; else x=a[i];if(j<0) y='0'; else y=b[j];z=x-'0'+y-'0';if(up) z+=1;if(z>9) {up=1;z%=10;} else up=0;c[k++]=z+'0';i--;j--;}if(up) c[k++]='1';i=0;c[k]='\0';for(k-=1;k>=0;k--)back[i++]=c[k];back[i]='\0';}5.精度计算——减法语法:sub(char s1[],char s2[],char t[]);参数:s1[]:被减数,用字符串表示,位数不限s2[]:减数,用字符串表示,位数不限t[]:结果,用字符串表示返回值:null注意:默认s1>=s2,程序未处理负数情况需要string.h源程序:void sub(char s1[],char s2[],char t[])我也可以做到..8 / 78{int i,l2,l1,k;l2=strlen(s2);l1=strlen(s1);t[l1]='\0';l1--;for (i=l2-1;i>=0;i--,l1--){if (s1[l1]-s2[i]>=0)t[l1]=s1[l1]-s2[i]+'0';else{t[l1]=10+s1[l1]-s2[i]+'0';s1[l1-1]=s1[l1-1]-1;}}k=l1;while(s1[k]<0) {s1[k]+=10;s1[k-1]-=1;k--;}while(l1>=0) {t[l1]=s1[l1];l1--;}loop:if (t[0]=='0') {l1=strlen(s1);for (i=0;i<l1-1;i++) t[i]=t[i+1];t[l1-1]='\0';goto loop;}if (strlen(t)==0) {t[0]='0';t[1]='\0';}}6.任意进制转换语法:conversion(char s1[],char s2[],char t[]);参数:s[]:转换前的数字s2[]:转换后的数字d1:原进制数d2:需要转换到的进制数返回值:null注意:高于9 的位数用大写'A'~'Z'表示,2~16 位进制通过验证源程序:void conversion(char s[],char s2[],long d1,long d2){我也可以做到..9 / 78long i,j,t,num;char c;num=0;for (i=0;s[i]!='\0';i++){if (s[i]<='9'&&s[i]>='0') t=s[i]-'0'; else t=s[i]-'A'+10;num=num*d1+t;}i=0;while(1){t=num%d2;if (t<=9) s2[i]=t+'0'; else s2[i]=t+'A'-10;num/=d2;if (num==0) break;i++;}for (j=0;j<i/2;j++){c=s2[j];s2[j]=s[i-j];s2[i-j]=c;}s2[i+1]='\0';}7.最大公约数、最小公倍数语法:resulet=hcf(int a,int b)、result=lcd(int a,int b)参数:a:int a,求最大公约数或最小公倍数b:int b,求最大公约数或最小公倍数返回值:返回最大公约数(hcf)或最小公倍数(lcd)注意:lcd 需要连同hcf 使用源程序:int hcf(int a,int b){int r=0;while(b!=0){r=a%b;a=b;DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDb=r;}return(a);我也可以做到..10 / 78}lcd(int u,int v,int h){return(u*v/h);}8.组合序列语法:m_of_n(int m, int n1, int m1, int* a, int head)参数:m:组合数C 的上参数n1:组合数C 的下参数m1:组合数C 的上参数,递归之用*a:1~n 的整数序列数组head:头指针返回值:null注意:*a 需要自行产生初始调用时,m=m1、head=0调用例子:求C(m,n)序列:m_of_n(m,n,m,a,0);源程序:void m_of_n(int m, int n1, int m1, int* a, int head){int i,t;if(m1<0 || m1>n1) return;if(m1==n1){return;}m_of_n(m,n1-1,m1,a,head); // 递归调用t=a[head];a[head]=a[n1-1+head];a[n1-1+head]=t;m_of_n(m,n1-1,m1-1,a,head+1); // 再次递归调用t=a[head];a[head]=a[n1-1+head];a[n1-1+head]=t;}9.快速傅立叶变换(FFT)语法:kkfft(double pr[],double pi[],int n,int k,double fr[],double fi[],intl,int il);参数:我也可以做到..11 / 78pr[n]:输入的实部pi[n]:数入的虚部n,k:满足n=2^kfr[n]:输出的实部fi[n]:输出的虚部l:逻辑开关,0 FFT,1 ifFTil:逻辑开关,0 输出按实部/虚部;1 输出按模/幅角返回值:null注意:需要math.h源程序:void kkfft(pr,pi,n,k,fr,fi,l,il)int n,k,l,il;double pr[],pi[],fr[],fi[];{int it,m,is,i,j,nv,l0; double p,q,s,vr,vi,poddr,poddi;for (it=0; it<=n-1; it++){m=it; is=0;for (i=0; i<=k-1; i++){j=m/2; is=2*is+(m-2*j); m=j;}fr[it]=pr[is]; fi[it]=pi[is];}pr[0]=1.0; pi[0]=0.0;p=6.283185306/(1.0*n);pr[1]=cos(p); pi[1]=-sin(p);if (l!=0) pi[1]=-pi[1];for (i=2; i<=n-1; i++){p=pr[i-1]*pr[1];q=pi[i-1]*pi[1];s=(pr[i-1]+pi[i-1])*(pr[1]+pi[1]);pr[i]=p-q; pi[i]=s-p-q;}for (it=0; it<=n-2; it=it+2){vr=fr[it]; vi=fi[it];fr[it]=vr+fr[it+1]; fi[it]=vi+fi[it+1];fr[it+1]=vr-fr[it+1]; fi[it+1]=vi-fi[it+1]; }m=n/2; nv=2;for (l0=k-2; l0>=0; l0--){我也可以做到..12 / 78m=m/2; nv=2*nv;for (it=0; it<=(m-1)*nv; it=it+nv)for (j=0; j<=(nv/2)-1; j++){p=pr[m*j]*fr[it+j+nv/2];q=pi[m*j]*fi[it+j+nv/2];s=pr[m*j]+pi[m*j];s=s*(fr[it+j+nv/2]+fi[it+j+nv/2]); poddr=p-q; poddi=s-p-q;fr[it+j+nv/2]=fr[it+j]-poddr;fi[it+j+nv/2]=fi[it+j]-poddi;fr[it+j]=fr[it+j]+poddr;fi[it+j]=fi[it+j]+poddi;}}if (l!=0)for (i=0; i<=n-1; i++){fr[i]=fr[i]/(1.0*n);fi[i]=fi[i]/(1.0*n);}if (il!=0)for (i=0; i<=n-1; i++){pr[i]=sqrt(fr[i]*fr[i]+fi[i]*fi[i]);if (fabs(fr[i])<0.000001*fabs(fi[i])) {if ((fi[i]*fr[i])>0) pi[i]=90.0;else pi[i]=-90.0;}DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDelsepi[i]=atan(fi[i]/fr[i])*360.0/6.283185306;}return;}10.Ronberg 算法计算积分语法:result=integral(double a,double b);参数:a:积分上限b:积分下限我也可以做到..13 / 78function f:积分函数返回值:f 在(a,b)之间的积分值注意:function f(x)需要自行修改,程序中用的是sina(x)/x 需要math.h默认精度要求是1e-5源程序:double f(double x){return sin(x)/x; //在这里插入被积函数}double integral(double a,double b){double h=b-a;double t1=(1+f(b))*h/2.0;int k=1;double r1,r2,s1,s2,c1,c2,t2;loop:double s=0.0;double x=a+h/2.0;while(x<b){s+=f(x);x+=h;}t2=(t1+h*s)/2.0;s2=t2+(t2-t1)/3.0;if(k==1){k++;h/=2.0;t1=t2;s1=s2;goto loop;}c2=s2+(s2-s1)/15.0;if(k==2){c1=c2;k++;h/=2.0;t1=t2;s1=s2;goto loop;}r2=c2+(c2-c1)/63.0;if(k==3){r1=r2; c1=c2;k++;h/=2.0;t1=t2;s1=s2;我也可以做到..14 / 78goto loop;}while(fabs(1-r1/r2)>1e-5){ r1=r2;c1=c2;k++;h/=2.0;t1=t2;s1=s2;goto loop;}return r2;}11.行列式计算语法:result=js(int s[][],int n)参数:s[][]:行列式存储数组n:行列式维数,递归用返回值:行列式值注意:函数中常数N 为行列式维度,需自行定义源程序:int js(s,n)int s[][N],n;{int z,j,k,r,total=0;int b[N][N];/*b[N][N]用于存放,在矩阵s[N][N]中元素s[0]的余子式*/if(n>2){for(z=0;z<n;z++){for(j=0;j<n-1;j++)for(k=0;k<n-1;k++)if(k>=z) b[j][k]=s[j+1][k+1]; elseb[j][k]=s[j+1][k];if(z%2==0) r=s[0][z]*js(b,n-1); /*递归调用*/else r=(-1)*s[0][z]*js(b,n-1);total=total+r;}}else if(n==2)total=s[0][0]*s[1][1]-s[0][1]*s[1][0];return total;我也可以做到..15 / 78}12.求排列组合数语法:result=P(long n,long m); / result=long C(long n,long m);参数:m:排列组合的上系数n:排列组合的下系数返回值:排列组合数注意:符合数学规则:m<=n源程序:long P(long n,long m){long p=1;while(m!=0){p*=n;n--;m--;}return p;}long C(long n,long m){long i,c=1;DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDi=m;while(i!=0){c*=n;n--;i--;}while(m!=0){c/=m;m--;}return c;}13.求某一天星期几语法:result=weekday(int N,int M,int d)参数:N,M,d:年月日,例如:2003,11,4返回值:0:星期天,1 星期一……注意:需要math.h适用于1582 年10 月15 日之后, 因为罗马教皇格里高利十三世在这一天启用新历法.源程序:我也可以做到..16 / 78int weekday(int N,int M,int d){int m,n,c,y,w;m=(M-2)%12;if (M>=3) n=N;else n=N-1;c=n/100;y=n%100;w=(int)(d+floor(13*m/5)+y+floor(y/4)+floor(c/4)-2*c)%7;while(w<0) w+=7;return w;}14.卡特兰(Catalan) 数列原理令h(1)=1,catalan 数满足递归式:h(n)= h(1)*h(n-1) + h(2)*h(n-2) + ... + h(n-1)h(1) (其中n>=2)该递推关系的解为:h(n)=c(2n-2,n-1)/n (n=1,2,3,...)1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440,9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420,24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, …1.括号化问题。
目录一、数学问题 (4)1.精度计算——大数阶乘 (4)2.精度计算——乘法(大数乘小数) (4)3.精度计算——乘法(大数乘大数) (5)4.精度计算——加法 (6)5.精度计算——减法 (7)6.任意进制转换 (8)7.最大公约数、最小公倍数 (9)8.组合序列 (10)9.快速傅立叶变换(FFT) (10)10.Ronberg 算法计算积分 (12)11.行列式计算 (14)12.求排列组合数 (15)13.求某一天星期几 (15)14.卡特兰(Catalan) 数列原理 (16)15.杨辉三角 (16)16.全排列 (17)17.匈牙利算法----最大匹配问题 (18)18.最佳匹配KM 算法 (20)二、字符串处理 (22)1.字符串替换 (22)2.字符串查找 (23)3.字符串截取 (24)4.LCS-最大公共子串长度 (24)5.LCS-最大公共子串长度 (25)6.数字转换为字符 (26)三、计算几何 (27)1.叉乘法求任意多边形面积 (27)2.求三角形面积 (27)3.两矢量间角度 (28)4.两点距离(2D、3D) (28)5.射向法判断点是否在多边形内部 (29)6.判断点是否在线段上 (30)7.判断两线段是否相交 (31)8.判断线段与直线是否相交 (32)9.点到线段最短距离 (32)10.求两直线的交点 (33)11.判断一个封闭图形是凹集还是凸集 (34)12.Graham 扫描法寻找凸包 (35)13.求两条线段的交点 (36)四、数论 (37)1.x 的二进制长度 (37)2.返回x 的二进制表示中从低到高的第i 位 (38)3.模取幂运算 (38)4.求解模线性方程 (39)5.求解模线性方程组(中国余数定理) (39)6.筛法素数产生器 (40)7.判断一个数是否素数 (41)8.求距阵最大和 (42)8.求一个数每一位相加之和 (43)10.质因数分解 (43)11.高斯消元法解线性方程组 (44)五、图论 (45)1.Prim 算法求最小生成树................................................. 45 2.Dijkstra 算法求单源最短路径.. (46)3.Bellman-ford 算法求单源最短路径 (47)4.Floyd-Warshall 算法求每对节点间最短路径 (48)5.解欧拉图 (49)六、排序/查找 (50)1.快速排序 (50)2.希尔排序 (51)3.选择法排序 (52)4.二分查找 (52)七、数据结构 (53)1.顺序队列 (53)2.顺序栈 (56)3.链表 (59)4.链栈 (63)5.二叉树 (66)八、高精度运算专题 (68)1.专题函数说明 (68)2.高精度数比较 (69)3.高精度数加法 (69)4.高精度数减法 (70)5.高精度乘10 (71)6.高精度乘单精度 (71)7.高精度乘高精度 (72)8.高精度除单精度 (72)9.高精度除高精度 (73)九、标准模板库的使用 (74)1.计算求和 (74)2.求数组中的最大值 (76)3. sort 和qsort (76)十、其他 (78)1.运行时间计算 (78)一、数学问题1.精度计算——大数阶乘语法:int result=factorial(int n);参数:n:n 的阶乘返回值:阶乘结果的位数注意:本程序直接输出n!的结果,需要返回结果请保留long a[] 需要math.h源程序: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;}if(c>0) {m++;a[m]=c;}}w=m*4+log10(a[m])+1;printf("\n%ld",a[m]);for(i=m-1;i>=0;i--) printf("%4.4ld",a[i]);return w;}我也可以做到..5 / 782.精度计算——乘法(大数乘小数)语法:mult(char c[],char t[],int m);参数:c[]:被乘数,用字符串表示,位数不限t[]:结果,用字符串表示m:乘数,限定10 以内返回值:null注意:需要string.h源程序:void mult(char c[],char t[],int m){int i,l,k,flag,add=0;char s[100];l=strlen(c);for (i=0;i<l;i++)s[l-i-1]=c[i]-'0';for (i=0;i<l;i++){k=s[i]*m+add;if (k>=10) {s[i]=k%10;add=k/10;flag=1;} else{s[i]=k;flag=0;add=0;}}if (flag) {l=i+1;s[i]=add;} else l=i;for (i=0;i<l;i++)t[l-1-i]=s[i]+'0'; t[l]='\0';}3.精度计算——乘法(大数乘大数)语法:mult(char a[],char b[],char s[]);参数:a[]:被乘数,用字符串表示,位数不限b[]:乘数,用字符串表示,位数不限t[]:结果,用字符串表示返回值:null注意:空间复杂度为o(n^2)需要string.h源程序:void mult(char a[],char b[],char s[]){我也可以做到..6 / 78int i,j,k=0,alen,blen,sum=0,res[65][65]={0},flag=0; char result[65];alen=strlen(a);blen=strlen(b);for (i=0;i<alen;i++)for (j=0;j<blen;j++) res[i][j]=(a[i]-'0')*(b[j]-'0');for (i=alen-1;i>=0;i--){for (j=blen-1;j>=0;j--) sum=sum+res[i+blen-j-1][j]; result[k]=sum%10;k=k+1;sum=sum/10;}for (i=blen-2;i>=0;i--){for (j=0;j<=i;j++) sum=sum+res[i-j][j];result[k]=sum%10;k=k+1;sum=sum/10;}if (sum!=0) {result[k]=sum;k=k+1;}for (i=0;i<k;i++) result[i]+='0';for (i=k-1;i>=0;i--) s[i]=result[k-1-i];s[k]='\0';while(1){if (strlen(s)!=strlen(a)&&s[0]=='0')strcpy(s,s+1);elsebreak;}}4.精度计算——加法语法:add(char a[],char b[],char s[]);参数:a[]:被加数,用字符串表示,位数不限b[]:加数,用字符串表示,位数不限s[]:结果,用字符串表示返回值:null注意:空间复杂度为o(n^2)我也可以做到..7 / 78需要string.h源程序:void add(char a[],char b[],char back[]){int i,j,k,up,x,y,z,l;char *c;if (strlen(a)>strlen(b)) l=strlen(a)+2; else l=strlen(b)+2; c=(char *) malloc(l*sizeof(char));i=strlen(a)-1;j=strlen(b)-1;k=0;up=0;while(i>=0||j>=0){if(i<0) x='0'; else x=a[i];if(j<0) y='0'; else y=b[j];z=x-'0'+y-'0';if(up) z+=1;if(z>9) {up=1;z%=10;} else up=0;c[k++]=z+'0';i--;j--;}if(up) c[k++]='1';i=0;c[k]='\0';for(k-=1;k>=0;k--)back[i++]=c[k];back[i]='\0';}5.精度计算——减法语法:sub(char s1[],char s2[],char t[]);参数:s1[]:被减数,用字符串表示,位数不限s2[]:减数,用字符串表示,位数不限t[]:结果,用字符串表示返回值:null注意:默认s1>=s2,程序未处理负数情况需要string.h源程序:void sub(char s1[],char s2[],char t[])我也可以做到..8 / 78{int i,l2,l1,k;l2=strlen(s2);l1=strlen(s1);t[l1]='\0';l1--;for (i=l2-1;i>=0;i--,l1--){if (s1[l1]-s2[i]>=0)t[l1]=s1[l1]-s2[i]+'0';else{t[l1]=10+s1[l1]-s2[i]+'0';s1[l1-1]=s1[l1-1]-1;}}k=l1;while(s1[k]<0) {s1[k]+=10;s1[k-1]-=1;k--;}while(l1>=0) {t[l1]=s1[l1];l1--;}loop:if (t[0]=='0') {l1=strlen(s1);for (i=0;i<l1-1;i++) t[i]=t[i+1];t[l1-1]='\0';goto loop;}if (strlen(t)==0) {t[0]='0';t[1]='\0';}}6.任意进制转换语法:conversion(char s1[],char s2[],char t[]);参数:s[]:转换前的数字s2[]:转换后的数字d1:原进制数d2:需要转换到的进制数返回值:null注意:高于9 的位数用大写'A'~'Z'表示,2~16 位进制通过验证源程序:void conversion(char s[],char s2[],long d1,long d2){我也可以做到..9 / 78long i,j,t,num;char c;num=0;for (i=0;s[i]!='\0';i++){if (s[i]<='9'&&s[i]>='0') t=s[i]-'0'; else t=s[i]-'A'+10;num=num*d1+t;}i=0;while(1){t=num%d2;if (t<=9) s2[i]=t+'0'; else s2[i]=t+'A'-10;num/=d2;if (num==0) break;i++;}for (j=0;j<i/2;j++){c=s2[j];s2[j]=s[i-j];s2[i-j]=c;}s2[i+1]='\0';}7.最大公约数、最小公倍数语法:resulet=hcf(int a,int b)、result=lcd(int a,int b)参数:a:int a,求最大公约数或最小公倍数b:int b,求最大公约数或最小公倍数返回值:返回最大公约数(hcf)或最小公倍数(lcd)注意:lcd 需要连同hcf 使用源程序:int hcf(int a,int b){int r=0;while(b!=0){r=a%b;a=b;b=r;}return(a);我也可以做到..10 / 78}lcd(int u,int v,int h){return(u*v/h);}8.组合序列语法:m_of_n(int m, int n1, int m1, int* a, int head)参数:m:组合数C 的上参数n1:组合数C 的下参数m1:组合数C 的上参数,递归之用*a:1~n 的整数序列数组head:头指针返回值:null注意:*a 需要自行产生初始调用时,m=m1、head=0调用例子:求C(m,n)序列:m_of_n(m,n,m,a,0);源程序:void m_of_n(int m, int n1, int m1, int* a, int head){int i,t;if(m1<0 || m1>n1) return;if(m1==n1){return;}m_of_n(m,n1-1,m1,a,head); // 递归调用t=a[head];a[head]=a[n1-1+head];a[n1-1+head]=t;m_of_n(m,n1-1,m1-1,a,head+1); // 再次递归调用t=a[head];a[head]=a[n1-1+head];a[n1-1+head]=t;}9.快速傅立叶变换(FFT)语法:kkfft(double pr[],double pi[],int n,int k,double fr[],double fi[],intl,int il);参数:我也可以做到..11 / 78pr[n]:输入的实部pi[n]:数入的虚部n,k:满足n=2^kfr[n]:输出的实部fi[n]:输出的虚部l:逻辑开关,0 FFT,1 ifFTil:逻辑开关,0 输出按实部/虚部;1 输出按模/幅角返回值:null注意:需要math.h源程序:void kkfft(pr,pi,n,k,fr,fi,l,il)int n,k,l,il;double pr[],pi[],fr[],fi[];{int it,m,is,i,j,nv,l0; double p,q,s,vr,vi,poddr,poddi;for (it=0; it<=n-1; it++){m=it; is=0;for (i=0; i<=k-1; i++){j=m/2; is=2*is+(m-2*j); m=j;}fr[it]=pr[is]; fi[it]=pi[is];}pr[0]=1.0; pi[0]=0.0;p=6.283185306/(1.0*n);pr[1]=cos(p); pi[1]=-sin(p);if (l!=0) pi[1]=-pi[1];for (i=2; i<=n-1; i++){p=pr[i-1]*pr[1];q=pi[i-1]*pi[1];s=(pr[i-1]+pi[i-1])*(pr[1]+pi[1]);pr[i]=p-q; pi[i]=s-p-q;}for (it=0; it<=n-2; it=it+2){vr=fr[it]; vi=fi[it];fr[it]=vr+fr[it+1]; fi[it]=vi+fi[it+1];fr[it+1]=vr-fr[it+1]; fi[it+1]=vi-fi[it+1]; }m=n/2; nv=2;for (l0=k-2; l0>=0; l0--){我也可以做到..12 / 78m=m/2; nv=2*nv;for (it=0; it<=(m-1)*nv; it=it+nv)for (j=0; j<=(nv/2)-1; j++){p=pr[m*j]*fr[it+j+nv/2];q=pi[m*j]*fi[it+j+nv/2];s=pr[m*j]+pi[m*j];s=s*(fr[it+j+nv/2]+fi[it+j+nv/2]); poddr=p-q; poddi=s-p-q;fr[it+j+nv/2]=fr[it+j]-poddr;fi[it+j+nv/2]=fi[it+j]-poddi;fr[it+j]=fr[it+j]+poddr;fi[it+j]=fi[it+j]+poddi;}}if (l!=0)for (i=0; i<=n-1; i++){fr[i]=fr[i]/(1.0*n);fi[i]=fi[i]/(1.0*n);}if (il!=0)for (i=0; i<=n-1; i++){pr[i]=sqrt(fr[i]*fr[i]+fi[i]*fi[i]);if (fabs(fr[i])<0.000001*fabs(fi[i])) {if ((fi[i]*fr[i])>0) pi[i]=90.0;else pi[i]=-90.0;}elsepi[i]=atan(fi[i]/fr[i])*360.0/6.283185306;}return;}10.Ronberg 算法计算积分语法:result=integral(double a,double b);参数:a:积分上限b:积分下限我也可以做到..13 / 78function f:积分函数返回值:f 在(a,b)之间的积分值注意:function f(x)需要自行修改,程序中用的是sina(x)/x 需要math.h默认精度要求是1e-5源程序:double f(double x){return sin(x)/x; //在这里插入被积函数}double integral(double a,double b){double h=b-a;double t1=(1+f(b))*h/2.0;int k=1;double r1,r2,s1,s2,c1,c2,t2;loop:double s=0.0;double x=a+h/2.0;while(x<b){s+=f(x);x+=h;}t2=(t1+h*s)/2.0;s2=t2+(t2-t1)/3.0;if(k==1){k++;h/=2.0;t1=t2;s1=s2;goto loop;}c2=s2+(s2-s1)/15.0;if(k==2){c1=c2;k++;h/=2.0;t1=t2;s1=s2;goto loop;}r2=c2+(c2-c1)/63.0;if(k==3){r1=r2; c1=c2;k++;h/=2.0;t1=t2;s1=s2;我也可以做到..14 / 78goto loop;}while(fabs(1-r1/r2)>1e-5){ r1=r2;c1=c2;k++;h/=2.0;t1=t2;s1=s2;goto loop;}return r2;}11.行列式计算语法:result=js(int s[][],int n)参数:s[][]:行列式存储数组n:行列式维数,递归用返回值:行列式值注意:函数中常数N 为行列式维度,需自行定义源程序:int js(s,n)int s[][N],n;{int z,j,k,r,total=0;int b[N][N];/*b[N][N]用于存放,在矩阵s[N][N]中元素s[0]的余子式*/if(n>2){for(z=0;z<n;z++){for(j=0;j<n-1;j++)for(k=0;k<n-1;k++)if(k>=z) b[j][k]=s[j+1][k+1]; elseb[j][k]=s[j+1][k];if(z%2==0) r=s[0][z]*js(b,n-1); /*递归调用*/else r=(-1)*s[0][z]*js(b,n-1);total=total+r;}}else if(n==2)total=s[0][0]*s[1][1]-s[0][1]*s[1][0];return total;我也可以做到..15 / 78}12.求排列组合数语法:result=P(long n,long m); / result=long C(long n,long m);参数:m:排列组合的上系数n:排列组合的下系数返回值:排列组合数注意:符合数学规则:m<=n源程序:long P(long n,long m){long p=1;while(m!=0){p*=n;n--;m--;}return p;}long C(long n,long m){long i,c=1;i=m;while(i!=0){c*=n;n--;i--;}while(m!=0){c/=m;m--;}return c;}13.求某一天星期几语法:result=weekday(int N,int M,int d)参数:N,M,d:年月日,例如:2003,11,4返回值:0:星期天,1 星期一……注意:需要math.h适用于1582 年10 月15 日之后, 因为罗马教皇格里高利十三世在这一天启用新历法.源程序:我也可以做到..16 / 78int weekday(int N,int M,int d){int m,n,c,y,w;m=(M-2)%12;if (M>=3) n=N;else n=N-1;c=n/100;y=n%100;w=(int)(d+floor(13*m/5)+y+floor(y/4)+floor(c/4)-2*c)%7;while(w<0) w+=7;return w;}14.卡特兰(Catalan) 数列原理令h(1)=1,catalan 数满足递归式:h(n)= h(1)*h(n-1) + h(2)*h(n-2) + ... + h(n-1)h(1) (其中n>=2)该递推关系的解为:h(n)=c(2n-2,n-1)/n (n=1,2,3,...)1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440,9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420,24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, …1.括号化问题。
河南大学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算法模板总结班级:计算机091 学号: 10921018 姓名:鲍杭目录数论 (1)高精度算法[1] (1)高精度加法 (2)高精度减法 (2)高精度乘法 (4)整型常量阶乘 (6)整型常量阶乘和 (6)高精度的乘方 (7)高精度除法 (7)带符号的数据运算 (9)广度优先搜索大数应用 (11)基于比较的排序算法 (12)插入排序 (12)选择排序 (13)冒泡排序 (13)堆排序 (13)归并排序 (14)快速排序 (15)希尔排序 (16)同余运算 (16)模线性方程问题 (16)计算a^n mod k (19)阶乘最后非0位 (20)素数篇 (20)线性筛法 (21)费马小定理 (22)MR素性测试 (22)欧拉函数问题 (22)巴赫猜想 (23)最大公约数 (25)最小公倍数 (25)不定方程求解 (25)概率因子分解Pollard 算法 (26)数值计算[2] (26)定积分计算(Romberg) (26)多项式求根(牛顿法) (28)周期性方程(追赶法) (30)组合论[3] (30)组合公式 (30)全组合排列 (31)非重复组合排列 (33)类循环组合排列 (34)普通选择性组合排列 (36)生成全子集组合排列 (37)非重复生成全子集组合排列 (38)一般组合 (39)排列组合生成 (40)生成gray码 (42)置换(polya) (42)字典序全排列 (43)字典序组合 (43)计算几何 (44)对于任意多边形求面积 (44)判断两线是否相交 (44)二分查找模板 (45)二分图匹配模板 (45)动态规划 (46)求局部最大和模板 (46)字符串 (47)字符计数应用 (47)最大子序列算法 (47)求最长公供子串(DP算法) (49)数据结构 (49)图论 (49)入度和出度表的转化 (49)生成树 (52)最小生成树 (57)关键路径 (60)迷宫算法的队列实现 (65)最短路径 (68)栈的相关操作 (76)一元多项式计算 (79)单链表的简单操作 (84)快速排序 (90)哈夫曼编码 (91)队列的简单操作 (95)KMP模式匹配算法 (98)常用的数学公式[4] (100)中国剩余定理 (100)基本几何公式 (100)欧拉公式 (101)划分问题: (103)Stirling公式 (103)皮克定理 (103)卡特兰数 (104)原理: (104)错排公式 (104)等比数列 (104)等差数列 (105)二次函数 (105)二次方程 (105)约瑟夫环 (106)多边形面积 (106)均值不等式的简介 (106)均值不等式的变形 (106)Lucas 定理 (107)斐波那契数列 (107)欧拉函数 (109)蚂蚁爬绳 (110)(a/b)%m (110)泰勒公式 (110)乘法与因式分解公式 (110)三角不等式 (111)某些数列的前n项和 (111)二项式展开公式 (111)三角函数公式 (111)常用系统函数 (113)将字符串转化为数字 (113)系统函数排序 (113)数论高精度算法[1]#include<stdio.h>#include<string.h>char c[2000];//全局变量,存储大数运算的结果char arr[1000];//高精度除以高精度的余数long z=0;//高精度除以低精度的余数int Judge(char ch[]){//判断字符串ch是否全为0,若全为0,返回0,否则返回1 int i,k;k=strlen(ch);for(i=0;i<k;i++)if(ch[i]!='0')return 0;return 1;}int Compare(char a[],char b[]){//比较字符串的大小,方法不同于strcmp函数,类似于整型常量的比较int lena,lenb,i;lena=strlen(a);lenb=strlen(b);if(lena<lenb)return -1;else if(lena>lenb)return 1;else{if(strcmp(a,b)==0)return 0;else{for(i=0;i<lena;i++){if(a[i]>b[i])return 1;if(a[i]<b[i])return -1;}return 0;}}}高精度加法/*算法:先确定a和b中的最大位数k,然后依照由低至高位的顺序进行加法运算。
注意进位,若高位有进位,则c的长度为k+1。
*/void BigNumberAdd(char a1[],char b1[]){int i,j,k,lena,lenb;int a[1000]={0},b[1000]={0},d[1000]={0};lena=strlen(a1);lenb=strlen(b1);//将加数与被加数化为整型数组,并且该数组的其他位为for(i=0;i<lena;i++)a[i]=a1[lena-i-1]-'0';for(i=0;i<lenb;i++)b[i]=b1[lenb-1-i]-'0';//当数组除了加数和被加数以外的整型数组元素均为0时,无需考虑lena和lenb的大小k=lena>lenb?lena:lenb;for(i=0;i<k;i++){d[i]=a[i]+b[i]+d[i];d[i+1]=d[i+1]+d[i]/10;d[i]=d[i]%10;}//若高位进while(d[k])k++;while(!d[k-1])k--;//001+0003=4//将整型数组逆着转变并赋值给c字符型数组for(j=0;j<k;j++)c[j]=d[k-j-1]+'0';if(Judge(c))//若全为0,则只输出一个strcpy(c,"0");}高精度减法/*算法:依照由低位至高位的顺序进行减法运算。
在每次位运算中,若出现不够减的情况,则向高位借位。
在进行了la的减法后,若最高位为0,则a的长度减。
若A、B大小未知,则需先判断大小。
*/void BigNumberSub(char a1[],char b1[]){//a1为被减数,b1为减数int lena,lenb,i,j,k,flag;int a[1000]={0},b[1000]={0},d[1000]={0};lena=strlen(a1);lenb=strlen(b1);if(Compare(a1,b1)>=0){//若被减数大于等于减数for(i=0;i<lena;i++)a[i]=a1[lena-1-i]-'0';for(i=0;i<lenb;i++)b[i]=b1[lenb-1-i]-'0';flag=0;//结果正的标志}else{//若被减数小于减数for(i=0;i<lenb;i++)a[i]=b1[lenb-1-i]-'0';for(i=0;i<lena;i++)b[i]=a1[lena-1-i]-'0';flag=1;//结果负的标志}k=lena>lenb?lena:lenb;for(i=0;i<k;i++){//大数减小数if(a[i]<b[i]){//若被减数不够减,向高位借一位a[i+1]--;d[i]=a[i]-b[i]+10;}elsed[i]=a[i]-b[i];}//若较高位已为0,并且不止1位时while(!d[i-1]){k--;i--;}//根据flag,输出有无"-"if(!flag){for(i=0;i<k;i++){//将结果转化为字符逆着赋给数组cif(!i&&!d[k-i-1])//若差的第一个字母为0,则马上跳过continue;c[i]=d[k-i-1]+'0';}}else{c[0]='-';for(i=1;i<=k;i++){//将结果转化为字符逆着赋给数组cif(i==1&&!d[k-i])//若差的第一个字母为0,则马上跳过continue;c[i]=d[k-i]+'0';//注意d的下标,不是k-i-1}}if(Judge(c))//若差全为0,则只输出一个strcpy(c,"0");}高精度乘法高精度乘以低精度/*算法:将多位数存入数组,低位在前、高位在后,然后用一位数去乘数组的各位,考虑进位,最后按正常顺序输出*/void BigNumMultiSmall(char a1[],int b1){int i,j,t;int a[2000]={0};//将字符串转化为整型数组,并逆置t=strlen(a1);for(i=0;i<t;i++)a[i]=a1[t-1-i]-'0';//整型数组的每个元素乘以b1,然后对其进行求余,整除,使其只有一位数a[0]=a[0]*b1;for(i=1;i<t;i++){a[i]*=b1;a[i]+=a[i-1]/10;a[i-1]=a[i-1]%10;}while(a[i-1]>9){//若最后一个元素大于9a[i]=a[i-1]/10;a[i-1]=a[i-1]%10;i++;}//将得到的整型数组逆置赋给字符串for(j=0;j<i;j++)c[j]=a[i-j-1]+'0';if(Judge(c))//若积全为0,则只输出一个0strcpy(c,"0");}高精度乘以高精度void BigNumMultiBig(char a1[],char b1[]){int i,j,k,lena,lenb;int a[1000]={0},b[1000]={0},d[2000]={0};//将字符串转化为整型数组,并逆置lena=strlen(a1);lenb=strlen(b1);for(i=0;i<lena;i++)a[i]=a1[lena-i-1]-'0';for(i=0;i<lenb;i++)b[i]=b1[lenb-i-1]-'0';//计算乘数从低位到高位以此乘以被乘数的低位到高位for(i=0;i<lena;i++)for(j=0;j<lenb;j++){d[i+j]=d[i+j]+a[i]*b[j];d[i+j+1]+=d[i+j]/10;d[i+j]=d[i+j]%10;}//根据高位是否为判断整型数组的位数k=lena+lenb;while(!d[k-1])k--;//积转化为字符型for(i=0;i<k;i++)c[i]=d[k-1-i]+'0';if(Judge(c))//若积全为0,则只输出一个1strcpy(c,"0");}整型常量阶乘void BigNumFact(int x){int i,k,m=0,a[1000]={0};a[0]=1;for(;x;x--){//m为在求阶乘过程中a的元素个数for(k=i=0;i<=m;i++){k=k+a[i]*x;//数组各个元素均乘以x(x递减),以完成阶乘的运算a[i]=k%10;k/=10;}while(k){a[++m]=k%10;k/=10;}}//阶乘的结果转化为字符型for(i=0;i<=m;i++)c[i]=a[m-i]+'0';if(Judge(c))//若结果全为,则只输出一个strcpy(c,"0");}整型常量阶乘和void BigNumFactAdd(int t) //可以改进,减少算法时间复杂度{int i;char sum[2000],d[2000];//对字符串进行初始化memset(d,0,sizeof(d));memset(sum,0,sizeof(sum));//分别求出相应i的阶乘然后相加for(i=t;i>0;i--){BigNumFact(i); //调用大数乘法。