我的ACM算法模板

合集下载

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

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&&degree[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&&degree[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数论相关模板

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算法--枚举方法(指数枚举,组合枚举)模板

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常用算法模板

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模板

核心算法——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 算法模板

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数论模板

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的次数。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 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的标号是排过序以后的不与输入的编号对应叉积判断直线相交情况,求交点这里也用到叉积的原理。

相关文档
最新文档