16个ACM经典算法介绍
Acm竞赛常用算法与数据结构

• 每次用堆取出x进行计算,O(mnlogmn)。
28
哈希表(Hash)
• 理论上查找速度最快的数据结构之一 • 缺点: 需要大量的内存 需要构造Key
29
Hash表的实现
• 数组 • 冲突解决法 • 开散列法 • 闭散列法 C++ sgi stl 实现
30
Hash Key的选取
• 数值: • 方法一:直接取余数(一般选取质数M最为除 数) • 方法二:平方取中法,即计算关键值的平方, 2 r 的表 再取中间r位形成一个大小为
7
常见题型
•Dynamic Programming(动 态规划) •Greedy(贪心) •Complete Search(穷举) •Flood Fill (种子填充)
8
常见题型
• Shortest Path (最短路径) • Recursive Search Techniques (回溯) • Minimum Spanning Tree (最小 生成树) • Knapsack(背包)
22
Parity(ceoi99)
• 从整个01序列肯定是无法入手的,因为它 的长度高达109。 • 从范围比较小的n入手。也就是说我们需要 对信息进行一些特殊的处理。 • a b even/odd,那么将元素b指向a-1, 边的权值是even/odd。 • 下面我们由样例来说明一下这个处理方法。
23
11
12
枚举法
• 又叫穷举法,它利用了计算机计算 速度快且准确的特点,是最为朴素 和有效的一种算法。
• 不是办法的办法
• 但有时却是最好的办法
13
Pizza Anyone? (ZOJ 1219)
• 题目大意: 你需要为你和你的朋友们订一个皮萨。 每个朋友都会告诉你他们想和不想放进皮萨 里的东西。 你是否能订一个皮萨,让他满足每个人 至少一个条件。 假设一共有16种东西可以放进皮萨。
ACM算法模板(吉林大学)

目录目录 (1)Graph 图论 (3)|DAG的深度优先搜索标记 (3)|无向图找桥 (3)|无向图连通度(割) (3)|最大团问题DP+DFS (3)|欧拉路径O(E) (3)|D IJKSTRA数组实现O(N^2) (3)|D IJKSTRA O(E* LOG E) (4)|B ELLMAN F ORD单源最短路O(VE) (4)|SPFA(S HORTEST P ATH F ASTER A LGORITHM) (4)|第K短路(D IJKSTRA) (5)|第K短路(A*) (5)|P RIM求MST (6)|次小生成树O(V^2) (6)|最小生成森林问题(K颗树)O(MLOGM) (6)|有向图最小树形图 (6)|M INIMAL S TEINER T REE (6)|T ARJAN强连通分量 (7)|弦图判断 (7)|弦图的PERFECT ELIMINATION点排列 (7)|稳定婚姻问题O(N^2) (7)|拓扑排序 (8)|无向图连通分支(DFS/BFS邻接阵) (8)|有向图强连通分支(DFS/BFS邻接阵)O(N^2) (8)|有向图最小点基(邻接阵)O(N^2) (9)|F LOYD求最小环 (9)|2-SAT问题 (9)Network 网络流 (11)|二分图匹配(匈牙利算法DFS实现) (11)|二分图匹配(匈牙利算法BFS实现) (11)|二分图匹配(H OPCROFT-C ARP的算法) (11)|二分图最佳匹配(KUHN MUNKRAS算法O(M*M*N))..11 |无向图最小割O(N^3) (12)|有上下界的最小(最大)流 (12)|D INIC最大流O(V^2*E) (12)|HLPP最大流O(V^3) (13)|最小费用流O(V*E* F).......................................13|最小费用流O(V^2* F). (14)|最佳边割集 (15)|最佳点割集 (15)|最小边割集 (15)|最小点割集(点连通度) (16)|最小路径覆盖O(N^3) (16)|最小点集覆盖 (16)Structure 数据结构 (17)|求某天是星期几 (17)|左偏树合并复杂度O(LOG N) (17)|树状数组 (17)|二维树状数组 (17)|T RIE树(K叉) (17)|T RIE树(左儿子又兄弟) (18)|后缀数组O(N* LOG N) (18)|后缀数组O(N) (18)|RMQ离线算法O(N*LOG N)+O(1) (19)|RMQ(R ANGE M INIMUM/M AXIMUM Q UERY)-ST算法(O(NLOGN +Q)) (19)|RMQ离线算法O(N*LOG N)+O(1)求解LCA (19)|LCA离线算法O(E)+O(1) (20)|带权值的并查集 (20)|快速排序 (20)|2台机器工作调度 (20)|比较高效的大数 (20)|普通的大数运算 (21)|最长公共递增子序列O(N^2) (22)|0-1分数规划 (22)|最长有序子序列(递增/递减/非递增/非递减) (22)|最长公共子序列 (23)|最少找硬币问题(贪心策略-深搜实现) (23)|棋盘分割 (23)|汉诺塔 (23)|STL中的PRIORITY_QUEUE (24)|堆栈 (24)|区间最大频率 (24)|取第K个元素 (25)|归并排序求逆序数 (25)|逆序数推排列数 (25)|二分查找 (25)|二分查找(大于等于V的第一个值) (25)|所有数位相加 (25)Number 数论 (26)|递推求欧拉函数PHI(I) (26)|单独求欧拉函数PHI(X) (26)|GCD最大公约数 (26)|快速GCD (26)|扩展GCD (26)|模线性方程 A * X = B (% N) (26)|模线性方程组 (26)|筛素数[1..N] (26)|高效求小范围素数[1..N] (26)|随机素数测试(伪素数原理) (26)|组合数学相关 (26)|P OLYA计数 (27)|组合数C(N, R) (27)|最大1矩阵 (27)|约瑟夫环问题(数学方法) (27)|约瑟夫环问题(数组模拟) (27)|取石子游戏1 (27)|集合划分问题 (27)|大数平方根(字符串数组表示) (28)|大数取模的二进制方法 (28)|线性方程组A[][]X[]=B[] (28)|追赶法解周期性方程 (28)|阶乘最后非零位,复杂度O(NLOGN) (29)递归方法求解排列组合问题 (30)|类循环排列 (30)|全排列 (30)|不重复排列 (30)|全组合 (31)|不重复组合 (31)|应用 (31)模式串匹配问题总结 (32)|字符串H ASH (32)|KMP匹配算法O(M+N) (32)|K ARP-R ABIN字符串匹配 (32)|基于K ARP-R ABIN的字符块匹配 (32)|函数名: STRSTR (32)|BM算法的改进的算法S UNDAY A LGORITHM (32)|最短公共祖先(两个长字符串) (33)|最短公共祖先(多个短字符串)...............................33Geometry 计算几何.. (34)|G RAHAM求凸包O(N* LOG N) (34)|判断线段相交 (34)|求多边形重心 (34)|三角形几个重要的点 (34)|平面最近点对O(N* LOG N) (34)|L IUCTIC的计算几何库 (35)|求平面上两点之间的距离 (35)|(P1-P0)*(P2-P0)的叉积 (35)|确定两条线段是否相交 (35)|判断点P是否在线段L上 (35)|判断两个点是否相等 (35)|线段相交判断函数 (35)|判断点Q是否在多边形内 (35)|计算多边形的面积 (35)|解二次方程A X^2+B X+C=0 (36)|计算直线的一般式A X+B Y+C=0 (36)|点到直线距离 (36)|直线与圆的交点,已知直线与圆相交 (36)|点是否在射线的正向 (36)|射线与圆的第一个交点 (36)|求点P1关于直线LN的对称点P2 (36)|两直线夹角(弧度) (36)ACM/ICPC竞赛之STL (37)ACM/ICPC竞赛之STL简介 (37)ACM/ICPC竞赛之STL--PAIR (37)ACM/ICPC竞赛之STL--VECTOR (37)ACM/ICPC竞赛之STL--ITERATOR简介 (38)ACM/ICPC竞赛之STL--STRING (38)ACM/ICPC竞赛之STL--STACK/QUEUE (38)ACM/ICPC竞赛之STL--MAP (40)ACM/ICPC竞赛之STL--ALGORITHM (40)STL IN ACM (41)头文件 (42)线段树 (43)求矩形并的面积(线段树+离散化+扫描线) (43)求矩形并的周长(线段树+离散化+扫描线) (44)Graph 图论/*==================================================*\| DAG的深度优先搜索标记| INIT: edge[][]邻接矩阵; pre[], post[], tag全置0;| CALL: dfstag(i, n); pre/post:开始/结束时间\*==================================================*/int edge[V][V], pre[V], post[V], tag;void dfstag(int cur, int n){ // vertex: 0 ~ n-1pre[cur] = ++tag;for (int i=0; i<n; ++i) if (edge[cur][i]) {if (0 == pre[i]) {printf("Tree Edge!\n");dfstag(i,n);} else {if (0 == post[i]) printf("Back Edge!\n");else if (pre[i] > pre[cur])printf("Down Edge!\n");else printf("Cross Edge!\n");}}post[cur] = ++tag;}/*==================================================*\| 无向图找桥| INIT: edge[][]邻接矩阵;vis[],pre[],anc[],bridge 置0;| CALL: dfs(0, -1, 1, n);\*==================================================*/int bridge, edge[V][V], anc[V], pre[V], vis[V];void dfs(int cur, int father, int dep, int n){ // vertex: 0 ~ n-1if (bridge) return;vis[cur] = 1; pre[cur] = anc[cur] = dep;for (int i=0; i<n; ++i) if (edge[cur][i]) {if (i != father && 1 == vis[i]) {if (pre[i] < anc[cur])anc[cur] = pre[i];//back edge}if (0 == vis[i]) { //tree edgedfs(i,cur,dep+1,n);if (bridge) return;if (anc[i] < anc[cur]) anc[cur] = anc[i];if (anc[i] > pre[cur]) { bridge = 1; return; } }}vis[cur] = 2;}/*==================================================*\| 无向图连通度(割)| INIT: edge[][]邻接矩阵;vis[],pre[],anc[],deg[]置为0;| CALL: dfs(0, -1, 1, n);| k=deg[0], deg[i]+1(i=1…n-1)为删除该节点后得到的连通图个数| 注意:0作为根比较特殊!\*==================================================*/int edge[V][V], anc[V], pre[V], vis[V], deg[V];void dfs(int cur, int father, int dep, int n){// vertex: 0 ~ n-1int cnt = 0;vis[cur] = 1; pre[cur] = anc[cur] = dep;for (int i=0; i<n; ++i) if (edge[cur][i]) {if (i != father && 1 == vis[i]) {if (pre[i] < anc[cur])anc[cur] = pre[i];//back edge}if (0 == vis[i]) { //tree edgedfs(i,cur,dep+1,n);++cnt; // 分支个数if (anc[i] < anc[cur]) anc[cur] = anc[i];if ((cur==0 && cnt>1) ||(cnt!=0 && anc[i]>=pre[cur]))++deg[cur];// link degree of a vertex }}vis[cur] = 2;} /*==================================================*\| 最大团问题 DP + DFS| INIT: g[][]邻接矩阵;| CALL: res = clique(n);\*==================================================*/int g[V][V], dp[V], stk[V][V], mx;int dfs(int n, int ns, int dep){if (0 == ns) {if (dep > mx) mx = dep;return 1;}int i, j, k, p, cnt;for (i = 0; i < ns; i++) {k = stk[dep][i]; cnt = 0;if (dep + n - k <= mx) return 0;if (dep + dp[k] <= mx) return 0;for (j = i + 1; j < ns; j++) {p=stk[dep][j];if (g[k][p]) stk[dep + 1][cnt++] = p;}dfs(n, cnt, dep + 1);}return 1;}int clique(int n){int i, j, ns;for (mx = 0, i = n - 1; i >= 0; i--) {// vertex: 0 ~ n-1for (ns = 0, j = i + 1; j < n; j++)if (g[i][j]) stk[1][ ns++ ] = j;dfs(n, ns, 1); dp[i] = mx;}return mx;}/*==================================================*\| 欧拉路径O(E)| INIT: adj[][]置为图的邻接表; cnt[a]为a点的邻接点个数;| CALL: elpath(0); 注意:不要有自向边\*==================================================*/int adj[V][V], idx[V][V], cnt[V], stk[V], top;int path(int v){for (int w ; cnt[v] > 0; v = w) {stk[ top++ ] = v;w = adj[v][ --cnt[v] ];adj[w][ idx[w][v] ] = adj[w][ --cnt[w] ];// 处理的是无向图—-边是双向的,删除v->w后,还要处理删除w->v}return v;}void elpath (int b, int n){ // begin from b int i, j;for (i = 0; i < n; ++i) // vertex: 0 ~ n-1 for (j = 0; j < cnt[i]; ++j)idx[i][ adj[i][j] ] = j;printf("%d", b);for (top = 0; path(b) == b && top != 0; ) {b = stk[ --top ];printf("-%d", b);}printf("\n");}/*==================================================*\| Dijkstra数组实现O(N^2)| Dijkstra --- 数组实现(在此基础上可直接改为STL的Queue实现)| lowcost[] --- beg到其他点的最近距离| path[] -- beg为根展开的树,记录父亲结点\*==================================================*/#define INF 0x03F3F3F3Fconst int N;int path[N], vis[N];void Dijkstra(int cost[][N], int lowcost[N], int n, int beg){ int i, j, min;memset(vis, 0, sizeof(vis));vis[beg] = 1;for (i=0; i<n; i++){lowcost[i] = cost[beg][i]; path[i] = beg;}lowcost[beg] = 0;path[beg] = -1; // 树根的标记int pre = beg;for (i=1; i<n; i++){min = INF;dist[v] = dist[u] + c;for (j=0; j<n; j++)// 下面的加法可能导致溢出,INF 不能取太大if (vis[j]==0 &&lowcost[pre]+cost[pre][j]<lowcost[j]){lowcost[j] =lowcost[pre] + cost[pre][j]; path[j] = pre; } for (j=0; j<n; j++) if (vis[j] == 0 && lowcost[j] < min){ min = lowcost[j]; pre = j; } vis[pre] = 1; } } /*==================================================*\ | Dijkstra O(E * log E) | INIT: 调用init(nv, ne)读入边并初始化; | CALL: dijkstra(n, src); dist[i]为src 到i 的最短距离 \*==================================================*/ #define typec int // type of cost const typec inf = 0x3f3f3f3f; // max of cost typec cost[E], dist[V]; int e, pnt[E], nxt[E], head[V], prev[V], vis[V]; struct qnode { int v; typec c; qnode (int vv = 0, typec cc = 0) : v(vv), c(cc) {} bool operator < (const qnode& r) const { return c>r.c; } }; void dijkstra(int n, const int src){ qnode mv; int i, j, k, pre; priority_queue<qnode> que; vis[src] = 1; dist[src] = 0; que.push(qnode(src, 0)); for (pre = src, i=1; i<n; i++) { for (j = head[pre]; j != -1; j = nxt[j]) { k = pnt[j]; if (vis[k] == 0 && dist[pre] + cost[j] < dist[k]){ dist[k] =dist[pre] + cost[j]; que.push(qnode(pnt[j], dist[k])); prev[k] = pre; } } while (!que.empty() && vis[que.top().v] == 1) que.pop(); if (que.empty()) break ; mv = que.top(); que.pop(); vis[pre = mv.v] = 1; } } inline void addedge(int u, int v, typec c){ pnt[e] = v; cost[e] = c; nxt[e] = head[u]; head[u] = e++; } void init(int nv, int ne){ int i, u, v; typec c; e = 0;memset(head, -1, sizeof (head));memset(vis, 0, sizeof (vis));memset(prev, -1, sizeof (prev));for (i = 0; i < nv; i++) dist[i] = inf;for (i = 0; i < ne; ++i) {scanf("%d%d%d", &u, &v, &c);// %d: type of cost addedge(u, v, c); // vertex: 0 ~ n-1, 单向边 }}/*==================================================*\| BellmanFord 单源最短路O(VE)| 能在一般情况下,包括存在负权边的情况下,解决单源最短路径问题| INIT: edge[E][3]为边表| CALL: bellman(src);有负环返回0;dist[i]为src 到i 的最短距| 可以解决差分约束系统: 需要首先构造约束图,构造不等式时>=表示求最小值, 作为最长路,<=表示求最大值, 作为最短路 (v-u <= c:a[u][v] = c )\*==================================================*/#define typec int // type of costconst typec inf=0x3f3f3f3f; // max of costint n, m, pre[V], edge[E][3];typec dist[V];int relax (int u, int v, typec c){if (dist[v] > dist[u] + c) {pre[v] = u; return 1; } return 0; } int bellman (int src){ int i, j;for (i=0; i<n; ++i) { dist[i] = inf; pre[i] = -1; } dist[src] = 0; bool flag; for (i=1; i<n; ++i){ flag = false; // 优化 for (j=0; j<m; ++j) { if( 1 == relax(edge[j][0], edge[j][1], edge[j][2]) ) flag = true; } if( !flag ) break; } for (j=0; j<m; ++j) { if (1 == relax(edge[j][0], edge[j][1], edge[j][2])) return 0; // 有负圈 } return 1; } /*==================================================*\ | SPFA(Shortest Path Faster Algorithm) Bellman-Ford 算法的一种队列实现,减少了不必要的冗余计算。
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竞赛简介

Parity(ceoi99)(肖天)
• 建立sum数组,sum[i]表示从1到i之和是奇(true)还是偶 (false),sum[0]=false。这样题目中给的任意问题(a,b) 的答案都可以用sum[b] xor sum[a-1]表示。 • 开始我们并不知道sum[1..n]的值,不妨设为false,这时任意 sum[a],sum[b]都是独立的。对于每对问答(a,b,c),都可以 知道sum[b] xor sum[a-1]=c,由此把sum[b]和sum[a-1] 联系起来。这步操作可以用并查集完成,对于问答(a,b,c)如 果sum[a-1],sum[b]不属于一个集合就把它们并起来,否则 如果sum[a-1] xor sum[b]不等于c则说明出现矛盾,输出总 句数,退出。 • 对于不出现矛盾的sum数组,对于每个集合分为两个部分,我 们指定其中一个部分为true,另一个部分为false,则可以确定 sum数组,利用sum[i] xor sum[i-1]可以求出第i位的数字, 由于不同集合之间没有问答出现,所以此数列是一可行解,证 明算法正确。
• 但有时却是最好的办法
22
Pizza Anyone? (ZOJ 1219)
• 题目大意: 你需要为你和你的朋友们订一个皮萨。 每个朋友都会告诉你他们想和不想放进皮萨 里的东西。 你是否能订一个皮萨,让他满足每个人 至少一个条件。 假设一共有16种东西可以放进皮萨。
23
2 65536
16
是个对计算机很 小的数
3
ACM
ACM (Association for Computing Machinery) 成立于计算机诞生次年,是目前计算机学界中历史最 悠久、最具权威性的组织,是推进信息技术专业人员 和学生提高技巧的主要力量。ACM通过提供前沿技 术信息和从理论到实践的转化,为其全球7.5万名成 员服务,并已经成为信息科技领域的一个基本信息来 源。
ACM_算法模板集史上最完整收藏版223页全免费版(1)

免费模板~~~ACM Standard Code LibraryHuang WeiSoftware EngineeringComputer and Software CollegeHangzhou Dianzi UniversityOctober,2008ACM算法模板集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中国余数定理(互素与非互素)8.Euler Function欧拉函数9.Farey总数9.Farey序列构造ler_Rabbin素数测试,Pollard_rho因式分解五.图论算法1.最小生成树(Kruscal算法)2.最小生成树(Prim算法)3.单源最短路径(Bellman-ford算法)4.单源最短路径(Dijkstra算法)5.全源最短路径(Folyd算法)6.拓扑排序7.网络预流和最大流8.网络最小费用最大流9.网络最大流(高度标号预流推进)10.最大团11.最大匹配(Hungary,HopcroftKarp算法)12.带权二分图最优匹配(KM算法)13.强连通分量(Kosaraju算法)14.强连通分量(Gabow算法)15.无向图割边割点和双连通分量16.最小树形图O(N^3)17.最小树形图O(VE)六.几何算法1.几何模板2.球面上两点最短距离3.三点求圆心坐标4.三角形几个重要的点七.专题讨论1.树状数组2.字典树3.后缀树4.线段树5.并查集6.二叉堆7.逆序数(归并排序)8.树状DP9.欧拉路10.八数码11.高斯消元法12.字符串匹配(KMP算法)13.全排列,全组合14.二维线段树15.稳定婚姻匹配16.后缀数组17.左偏树18.标准RMQ-ST19.度限制最小生成树20.最优比率生成树(0/1分数规划)21.最小花费置换22.区间K大数23.LCA-RMQ-ST24.LCA–Tarjan25.指数型母函数26.指数型母函数(大数据)27.AC自动机(字典树+KMP)28.FFT(大数乘法)29.二分图网络最大流最小割30.混合图欧拉回路31.无源汇上下界网络流32.二分图最小点权覆盖33.带约束的轨道计数(Burnside引理)34.三分法求函数波峰35.单词计数,DFA自动机,Trie图(完全AC自动机)36.字符串和数值hash37.滚动队列,前向星表示法38.最小点基,最小权点基39.LCSubsequence O(N^2/logN)40.伸展树41.Treap42.0/1分数规划K约束43.表达式求值44.乘除法博弈,Wythoff博弈45.状态压缩的积木型DP46.解一般线性方程组(消元法)47.块状链表48.Factor Oracle第一章常用函数和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)return0;else return1;}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]="24hello",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:011211i i i n n F F F F F F −−===+⎡⎤⎥==⎥⎠⎦2.Lucas Number1,3,4,7,11,18,29,47,76,123...Formula:n nn L =+⎝⎠⎝⎠3.Catalan Number1,2,5,14,42,132,429,1430,4862,16796,58786,208012…Formula:110(2,)1*n n n i n ii C n n Cat n Cat Cat Cat −−−==+=∑Application:1)将n +2边形沿弦切割成n 个三角形的不同切割数Sample:n =2;n =3;2)n +1个数相乘,给每两个元素加上括号的不同方法数Sample:n =2;(1(23)),((12)3)n =3;(1(2(34))),(1((23)4)),((12)(34)),((1(23))4),(((12)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:,1,11,0 (0 || ) (1)n m n m n m m n m S S m S n m −−−=<⎧⎨+×>≥⎩,01(1)(,)()!m i n n m i S C m i m i m ==−××−∑Special Cases:,0,11,2,3,1,01211(3323)6(,2)1n n n n n n n n n n n S S S S S C n S −−===−=−×+==5.Bell Numbern 个元素集合所有的划分数Formula:,0nn n ii B S ==∑6.Stirling's Approximation!nn n e ⎞=⎟⎠7.Sum of Reciprocal ApproximationEulerGamma =0.57721566490153286060651209;11ln() ()n i n EulerGamma n i==+→∞∑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:121212(1) (2)n n n Y Y Y Y n Y n −−===+−×>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.错排公式121201(1)()n n n D D D n D D −−===−×+11.三角形内切圆半径公式22a b cp s sr a b c++===++12.三角形外接圆半径公式4abcR s=13.圆內接四边形面积公式2a b c dp s +++==14.基础数论公式1)模取幂%((((%)*)%))%n a b a b a b b=…2)n 的约数的个数若n 满足1212m n n n m n p p p =+++…,则n 的约数的个数为12(1)(1)(1)m n n n +++…第三章大数模板typedef int hugeint;//应不大于,以防乘法时溢出const int Base=1000;const int Capacity=1000;struct xnum{int Len;int Data[Capacity];xnum():Len(0){}xnum(const xnum&V):Len(V.Len){memcpy(Data,V.Data,Len*sizeof*Data);}xnum(int V):Len(0){for(;V>0;V/=Base)Data[Len++]=V%Base;}xnum(char S[]);xnum&operator=(const xnum&V){Len=V.Len;memcpy(Data,V.Data,Len*sizeof*Data);return*this;}int&operator[](int Index){return Data[Index];}int operator[](int Index)const{return Data[Index];}void print(){printf("%d",Len==0?0:Data[Len-1]);for(int i=Len-2;i>=0;i--)for(int j=Base/10;j>0;j/=10)printf("%d",Data[i]/j%10);}};xnum::xnum(char S[]){int I,J;Data[Len=0]=0;J=1;for(I=strlen(S)-1;I>=0;I--){Data[Len]+=(S[I]-'0')*J;J*=10;if(J>=Base)J=1,Data[++Len]=0;}if(Data[Len]>0)Len++;}int compare(const xnum&A,const xnum&B){int I;if(A.Len!=B.Len)return A.Len>B.Len?1:-1;for(I=A.Len-1;I>=0&&A[I]==B[I];I--);if(I<0)return0;return A[I]>B[I]?1:-1;}xnum operator+(const xnum&A,const xnum&B){xnum R;int I;int Carry=0;for(I=0;I<A.Len||I<B.Len||Carry>0;I++) {if(I<A.Len)Carry+=A[I];if(I<B.Len)Carry+=B[I];R[I]=Carry%Base;Carry/=Base;}R.Len=I;return R;}xnum operator-(const xnum&A,const xnum&B){xnum R;int Carry=0;R.Len=A.Len;int I;for(I=0;I<R.Len;I++){R[I]=A[I]-Carry;if(I<B.Len)R[I]-=B[I];if(R[I]<0)Carry=1,R[I]+=Base;else Carry=0;}while(R.Len>0&&R[R.Len-1]==0)R.Len--;return R;}xnum operator*(const xnum&A,const int B){int I;if(B==0)return0;xnum R;hugeint Carry=0;for(I=0;I<A.Len||Carry>0;I++){if(I<A.Len)Carry+=hugeint(A[I])*B;R[I]=Carry%Base;Carry/=Base;}R.Len=I;return R;}xnum operator*(const xnum&A,const xnum&B){int I;if(B.Len==0)return0;xnum R;for(I=0;I<A.Len;I++){hugeint Carry=0;for(int J=0;J<B.Len||Carry>0;J++){if(J<B.Len)Carry+=hugeint(A[I])*B[J];if(I+J<R.Len)Carry+=R[I+J];if(I+J>=R.Len)R[R.Len++]=Carry%Base;else R[I+J]=Carry%Base;Carry/=Base;}}return R;}xnum operator/(const xnum&A,const int B){xnum R;int I;hugeint C=0;for(I=A.Len-1;I>=0;I--){C=C*Base+A[I];R[I]=C/B;C%=B;}R.Len=A.Len;while(R.Len>0&&R[R.Len-1]==0)R.Len--;return R;}//divxnum operator/(const xnum&A,const xnum&B){int I;xnum R,Carry=0;int Left,Right,Mid;for(I=A.Len-1;I>=0;I--){Carry=Carry*Base+A[I];Left=0;Right=Base-1;while(Left<Right){Mid=(Left+Right+1)/2;if(compare(B*Mid,Carry)<=0)Left=Mid;else Right=Mid-1;}R[I]=Left;Carry=Carry-B*Left;}R.Len=A.Len;while(R.Len>0&&R[R.Len-1]==0)R.Len--;return R;}//modxnum operator%(const xnum&A,const xnum&B){int I;xnum R,Carry=0;int Left,Right,Mid;for(I=A.Len-1;I>=0;I--){Carry=Carry*Base+A[I];Left=0;Right=Base-1;while(Left<Right){Mid=(Left+Right+1)/2;if(compare(B*Mid,Carry)<=0)Left=Mid;else Right=Mid-1;}R[I]=Left;Carry=Carry-B*Left;}R.Len=A.Len;while(R.Len>0&&R[R.Len-1]==0)R.Len--;return Carry;}istream&operator>>(istream&In,xnum&V){char Ch;for(V=0;In>>Ch;){V=V*10+(Ch-'0');if(cin.peek()<='')break;}return In;}ostream&operator<<(ostream&Out,const xnum&V){int I;Out<<(V.Len==0?0:V[V.Len-1]);for(I=V.Len-2;I>=0;I--)for(int J=Base/10;J>0;J/=10)Out<<V[I]/J%10;return Out;}xnum gcd(xnum a,xnum b){if(compare(b,0)==0)return a;else return gcd(b,a%b);}int div(char*A,int B){int I;int C=0;int Alen=strlen(A);for(I=0;I<Alen;I++){C=C*Base+A[I]-'0';C%=B;}return C;}xnum C(int n,int m){int i;xnum sum=1;for(i=n;i>=n-m+1;i--)sum=sum*i;for(i=1;i<=m;i++)sum=sum/i;return sum;}#define MAXN9999#define DLEN4class BigNum{private:int a[1000];//可以控制大数的位数int len;//大数长度public:BigNum(){len=1;memset(a,0,sizeof(a));} BigNum(const int);BigNum(const char*);BigNum(const BigNum&);BigNum&operator=(const BigNum&);BigNum operator+(const BigNum&)const;BigNum operator-(const BigNum&)const;BigNum operator*(const BigNum&)const;BigNum operator/(const int&)const;BigNum operator^(const int&)const;int operator%(const int&)const;bool operator>(const BigNum&T)const;void print();};BigNum::BigNum(const int b){int c,d=b;len=0;memset(a,0,sizeof(a));while(d>MAXN){c=d-(d/(MAXN+1))*(MAXN+1);d=d/(MAXN+1);a[len++]=c;}a[len++]=d;}BigNum::BigNum(const char*s){int t,k,index,l,i;memset(a,0,sizeof(a));l=strlen(s);len=l/DLEN;if(l%DLEN)len++;index=0;for(i=l-1;i>=0;i-=DLEN){t=0;k=i-DLEN+1;if(k<0)k=0;for(int j=k;j<=i;j++)t=t*10+s[j]-'0';a[index++]=t;}}BigNum::BigNum(const BigNum&T):len(T.len){ int i;memset(a,0,sizeof(a));for(i=0;i<len;i++)a[i]=T.a[i];}BigNum&BigNum::operator=(const BigNum&n){ len=n.len;memset(a,0,sizeof(a));int i;for(i=0;i<len;i++)a[i]=n.a[i];return*this;}BigNum BigNum::operator+(const BigNum&T)const{ BigNum t(*this);int i,big;//位数big=T.len>len?T.len:len;for(i=0;i<big;i++){t.a[i]+=T.a[i];if(t.a[i]>MAXN){t.a[i+1]++;t.a[i]-=MAXN+1;}}if(t.a[big]!=0)t.len=big+1;else t.len=big;return t;}BigNum BigNum::operator-(const BigNum&T)const{ int i,j,big;bool flag;BigNum t1,t2;if(*this>T){t1=*this;t2=T;flag=0;}else{t1=T;t2=*this;flag=1;}big=t1.len;for(i=0;i<big;i++){if(t1.a[i]<t2.a[i]){j=i+1;while(t1.a[j]==0)j++;t1.a[j--]--;while(j>i)t1.a[j--]+=MAXN;t1.a[i]+=MAXN+1-t2.a[i];}else t1.a[i]-=t2.a[i];}t1.len=big;while(t1.a[len-1]==0&&t1.len>1){t1.len--;big--;}if(flag)t1.a[big-1]=0-t1.a[big-1];return t1;}BigNum BigNum::operator*(const BigNum&T)const{BigNum ret;int i,j,up;int temp,temp1;for(i=0;i<len;i++){up=0;for(j=0;j<T.len;j++){temp=a[i]*T.a[j]+ret.a[i+j]+up;if(temp>MAXN){temp1=temp-temp/(MAXN+1)*(MAXN+1);up=temp/(MAXN+1);ret.a[i+j]=temp1;}else{up=0;ret.a[i+j]=temp;}}if(up!=0)ret.a[i+j]=up;}ret.len=i+j;while(ret.a[ret.len-1]==0&&ret.len>1)ret.len--;return ret;}BigNum BigNum::operator/(const int&b)const{BigNum ret;int i,down=0;for(i=len-1;i>=0;i--){ret.a[i]=(a[i]+down*(MAXN+1))/b;down=a[i]+down*(MAXN+1)-ret.a[i]*b;}ret.len=len;while(ret.a[ret.len-1]==0&&ret.len>1)ret.len--;return ret;}int BigNum::operator%(const int&b)const{int i,d=0;for(i=len-1;i>=0;i--){d=((d*(MAXN+1))%b+a[i])%b;}return d;}BigNum BigNum::operator^(const int&n)const{BigNum t,ret(1);if(n<0)exit(-1);if(n==0)return1;if(n==1)return*this;int m=n;while(m>1){t=*this;int i;for(i=1;i<<1<=m;i<<=1){t=t*t;}m-=i;ret=ret*t;if(m==1)ret=ret*(*this);}return ret;}bool BigNum::operator>(const BigNum&T)const{ int ln;if(len>T.len)return true;else if(len==T.len){ln=len-1;while(a[ln]==T.a[ln]&&ln>=0)ln--;if(ln>=0&&a[ln]>T.a[ln])return true;else return false;}else return false;}void BigNum::print(){int i;cout<<a[len-1];for(i=len-2;i>=0;i--){cout.width(DLEN);cout.fill('0');cout<<a[i];}}//读取整数const int ok=1;int get_val(int&ret){ret=0;char ch;while((ch=getchar())>'9'||ch<'0');do{ret=ret*10+ch-'0';}while((ch=getchar())<='9'&&ch>='0');return ok;}//带负数int get_val(int&ret){ret=0;char ch;bool neg=false;while(((ch=getchar())>'9'||ch<'0')&&ch!='-');if(ch=='-'){neg=true;while((ch=getchar())>'9'||ch<'0');}do{ret=ret*10+ch-'0';}while((ch=getchar())<='9'&&ch>='0');ret=(neg?-ret:ret);return ok;}//读取整数,可判EOF和EOLconst int eof=-1;const int eol=-2;int get_val(int&ret){ret=0;char ch;while(((ch=getchar())>'9'||ch<'0')&&ch!=EOF);if(ch==EOF)return eof;do{ret=ret*10+ch-'0';}while((ch=getchar())<='9'&&ch>='0');if(ch=='\n')return eol;return ok;}//读取浮点数int get_val(double&ret){ret=0;double base=0.1;char ch;bool dot=false,neg=false;while(((ch=getchar())>'9'||ch<'0')&&ch!='.'&&ch!='-');if(ch=='-'){neg=true;while(((ch=getchar())>'9'||ch<'0')&&ch!='.'&&ch!='-');}do{if(ch=='.'){dot=true;continue;}if(dot){ret+=(ch-'0')*base;base*=0.1;}else ret=ret*10+(ch-'0');}while(((ch=getchar())<='9'&&ch>='0')||ch=='.');ret=(neg?-ret:ret);return ok;}typedef long long LL;//LL MultiMod(LL a,LL b,LL c){//if(b)//return(a*(b&1)%c+(MultiMod(a,b>>1,c)<<1))%c; //return0;//}LL MultiMod(LL a,LL b,LL c){LL ret=0,d=a;for(;b;b>>=1,d<<=1,d%=c)if((b&1))ret=(ret+d)%c;return ret;}//128-bits integer's power with mod in O(64*LogN)LL ModPower(LL base,LL exp,LL mod){LL ret=1;for(;exp;exp>>=1,base=MultiMod(base,base,mod)) if((exp&1))ret=MultiMod(ret,base,mod);return ret;}第四章数论算法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,gcd;//可以减少扩展欧几里德溢出的可能gcd=GCD(a,n);if(b%gcd!=0){cout<<"no solution"<<endl;return;}a/=gcd;b/=gcd;n/=gcd;d=extended_euclid(a,n,x,y);if(b%d==0){x0=(x*(b/d))%n;//x0:basic solutionint ans=n;//min x=(x0%(n/d)+(n/d))%(n/d)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,ret;ret=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);ret=(ret+y*m*b[i])%n;}return(n+ret%n)%n;}//m≡r[i](mod a[i])//a[i]可以不互素//-1表示无解/*Pku2891Strange Way to Express Integers假设C≡A1(mod B1),C≡A2(mod B2)。
C语言入门必学—10个经典C语言算法

C语言入门必学—10个经典C语言算法C语言是一种广泛使用的编程语言,具有高效、灵活和易学的特点。
它不仅在软件开发中被广泛应用,也是计算机科学专业的必修课。
在学习C语言的过程中,掌握一些经典的算法是非常重要的。
本文将介绍10个经典C语言算法,帮助读者更好地了解和掌握C语言。
一、冒泡排序算法(Bubble Sort)冒泡排序算法是最简单、也是最经典的排序算法之一。
它通过不断比较相邻的元素并交换位置,将最大(或最小)的元素逐渐“冒泡”到数组的最后(或最前)位置。
二、选择排序算法(Selection Sort)选择排序算法是一种简单但低效的排序算法。
它通过不断选择最小(或最大)的元素,并与未排序部分的第一个元素进行交换,将最小(或最大)的元素逐渐交换到数组的前面(或后面)。
三、插入排序算法(Insertion Sort)插入排序算法是一种简单且高效的排序算法。
它通过将数组分为已排序和未排序两个部分,依次将未排序部分的元素插入到已排序部分的合适位置。
四、快速排序算法(Quick Sort)快速排序算法是一种高效的排序算法。
它采用了分治的思想,通过将数组分为较小和较大两部分,并递归地对两部分进行排序,最终达到整个数组有序的目的。
五、归并排序算法(Merge Sort)归并排序算法是一种高效的排序算法。
它采用了分治的思想,将数组一分为二,递归地对两个子数组进行排序,并将结果合并,最终得到有序的数组。
六、二分查找算法(Binary Search)二分查找算法是一种高效的查找算法。
它通过不断将查找范围折半,根据中间元素与目标值的大小关系,缩小查找范围,最终找到目标值所在的位置。
七、递归算法(Recursive Algorithm)递归算法是一种通过自我调用的方式解决问题的算法。
在C语言中,递归算法常用于解决树的遍历、问题分解等情况。
八、斐波那契数列算法(Fibonacci Sequence)斐波那契数列是一列数字,其中每个数字都是前两个数字的和。
ACM经典的题目代码

目录一.数论 41.阶乘最后非零位 42. 模线性方程(组) 43. 素数表64. 素数随机判定(miller_rabin) 65. 质因数分解76. 最大公约数欧拉函数8二.图论_匹配91. 二分图最大匹配(hungary邻接表形式) 92. 二分图最大匹配(hungary邻接表形式,邻接阵接口) 103. 二分图最大匹配(hungary邻接阵形式) 104. 二分图最大匹配(hungary正向表形式) 115. 二分图最佳匹配(kuhn_munkras邻接阵形式) 116. 一般图匹配(邻接表形式) 127. 一般图匹配(邻接表形式,邻接阵接口) 138. 一般图匹配(邻接阵形式) 149. 一般图匹配(正向表形式) 15三.图论_生成树161. 最小生成树(kruskal邻接表形式) 162. 最小生成树(kruskal正向表形式) 173. 最小生成树(prim+binary_heap邻接表形式) 194. 最小生成树(prim+binary_heap正向表形式) 205. 最小生成树(prim+mapped_heap邻接表形式) 216. 最小生成树(prim+mapped_heap正向表形式) 227. 最小生成树(prim邻接阵形式) 238. 最小树形图(邻接阵形式) 24四.图论_网络流251. 上下界最大流(邻接表形式) 252. 上下界最大流(邻接阵形式) 263. 上下界最小流(邻接表形式) 274. 上下界最小流(邻接阵形式) 295. 最大流(邻接表形式) 306. 最大流(邻接表形式,邻接阵接口) 317. 最大流(邻接阵形式) 328. 最大流无流量(邻接阵形式) 329. 最小费用最大流(邻接阵形式) 33五. 图论_最短路径341. 最短路径(单源bellman_ford邻接阵形式) 342. 最短路径(单源dijkstra_bfs邻接表形式) 353. 最短路径(单源dijkstra_bfs正向表形式) 354. 最短路径(单源dijkstra+binary_heap邻接表形式) 365. 最短路径(单源dijkstra+binary_heap正向表形式) 376. 最短路径(单源dijkstra+mapped_heap邻接表形式) 387. 最短路径(单源dijkstra+mapped_heap正向表形式) 398. 最短路径(单源dijkstra邻接阵形式) 409. 最短路径(多源floyd_warshall邻接阵形式) 40六. 图论_连通性411. 无向图关键边(dfs邻接阵形式) 412. 无向图关键点(dfs邻接阵形式) 423. 无向图块(bfs邻接阵形式) 434. 无向图连通分支(bfs邻接阵形式) 435. 无向图连通分支(dfs邻接阵形式) 446. 有向图强连通分支(bfs邻接阵形式) 447. 有向图强连通分支(dfs邻接阵形式) 458. 有向图最小点基(邻接阵形式) 46七. 图论_应用461.欧拉回路(邻接阵形式) 462. 前序表转化473. 树的优化算法484. 拓扑排序(邻接阵形式). 495. 最佳边割集506. 最佳顶点割集517. 最小边割集528. 最小顶点割集539. 最小路径覆盖55八. 图论_NP搜索551. 最大团(n小于64)(faster) 552. 最大团58九. 组合591. 排列组合生成592. 生成gray码603. 置换(polya) 614. 字典序全排列615. 字典序组合626. 组合公式62十. 数值计算631. 定积分计算(Romberg) 632. 多项式求根(牛顿法) 643. 周期性方程(追赶法) 66十一. 几何671. 多边形672. 多边形切割703. 浮点函数714. 几何公式765. 面积786. 球面797. 三角形798. 三维几何819. 凸包(graham) 8910. 网格(pick) 9111. 圆9212. 整数函数9413. 注意96十二. 结构971. 并查集972. 并查集扩展(friend_enemy) 983. 堆(binary) 984. 堆(mapped) 995. 矩形切割996. 线段树1007. 线段树扩展1028. 线段树应用1059. 子段和10510. 子阵和105十三. 其他1061. 分数1062. 矩阵1083. 日期1104. 线性方程组(gauss) 1115. 线性相关113十四. 应用1141. joseph 1142. N皇后构造解 1153. 布尔母函数1154. 第k元素1165. 幻方构造1166. 模式匹配(kmp) 1187. 逆序对数1188. 字符串最小表示1199. 最长公共单调子序列11910. 最长子序列12011. 最大子串匹配12112. 最大子段和12213. 最大子阵和123一.数论1.阶乘最后非零位//求阶乘最后非零位,复杂度O(nlogn)//返回该位,n以字符串方式传入#include <string.h>#define MAXN 10000int lastdigit(char* buf){const int mod[20]={1,1,2,6,4,2,2,4,2,8,4,4,8,4,6,8,8,6,8,2};int len=strlen(buf),a[MAXN],i,c,ret=1;if (len==1)return mod[buf[0]-'0'];for (i=0;i<len;i++)a[i]=buf[len-1-i]-'0';for (;len;len-=!a[len-1]){ret=ret*mod[a[1]%2*10+a[0]]%5;for (c=0,i=len-1;i>=0;i--)c=c*10+a[i],a[i]=c/5,c%=5;}return ret+ret%2*5;}2. 模线性方程(组)#ifdef WIN32typedef __int64 i64;#elsetypedef long long i64;#endif//扩展Euclid求解gcd(a,b)=ax+byint 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;}//计算m^a, O(loga), 本身没什么用, 注意这个按位处理的方法:-Pint exponent(int m,int a){int ret=1;for (;a;a>>=1,m*=m)if (a&1)ret*=m;return ret;}//计算幂取模a^b mod n, O(logb)int modular_exponent(int a,int b,int n){ //a^b mod nint ret=1;for (;b;b>>=1,a=(int)((i64)a)*a%n)if (b&1)ret=(int)((i64)ret)*a%n;return ret;}//求解模线性方程ax=b (mod n)//返回解的个数,解保存在sol[]中//要求n>0,解的范围0..n-1int modular_linear(int a,int b,int n,int* sol){int d,e,x,y,i;d=ext_gcd(a,n,x,y);if (b%d)return 0;e=(x*(b/d)%n+n)%n;for (i=0;i<d;i++)sol[i]=(e+i*(n/d))%n;return d;}//求解模线性方程组(中国余数定理)// 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;}3. 素数表//用素数表判定素数,先调用initprimeint plist[10000],pcount=0;int prime(int n){int i;if((n!=2&&!(n%2))||(n!=3&&!(n%3))||(n!=5&&!(n%5))||(n!=7&&! (n%7)))return 0;for (i=0;plist[i]*plist[i]<=n;i++)if (!(n%plist[i]))return 0;return n>1;}void initprime(){int i;for (plist[pcount++]=2,i=3;i<50000;i++)if (prime(i))plist[pcount++]=i;}4. 素数随机判定(miller_rabin)//miller rabin//判断自然数n是否为素数//time越高失败概率越低,一般取10到50#include <stdlib.h>#ifdef WIN32typedef __int64 i64;#elsetypedef long long i64;#endifint modular_exponent(int a,int b,int n){ //a^b mod nint ret;for (;b;b>>=1,a=(int)((i64)a)*a%n)if (b&1)ret=(int)((i64)ret)*a%n;return ret;}// Carmicheal number: 561,41041,,int miller_rabin(int n,int time=10){if(n==1||(n!=2&&!(n%2))||(n!=3&&!(n%3))||(n!=5&&!(n%5))||(n!= 7&&!(n%7)))return 0;while (time--)if(modular_exponent(((rand()&0x7fff<<16)+rand()&0x7fff+rand() &0x7fff)%(n-1)+1,n-1,n)!=1)return 0;return 1;}5. 质因数分解//分解质因数//prime_factor()传入n, 返回不同质因数的个数//f存放质因数,nf存放对应质因数的个数//先调用initprime(),其中第二个initprime()更快#include<iostream>#include<cstdio>#include<cmath>using namespace std;#define MAXN#define PSIZEint plist[PSIZE], pcount=0;int prime(int n){int i;if((n!=2&&!(n%2))||(n!=3&&!(n%3))||(n!=5&&!(n%5))||(n!=7&&! (n%7)))return 0;for (i=0;plist[i]*plist[i]<=n;++i)if (!(n%plist[i]))return 0;return n>1;}void initprime(){int i;for (plist[pcount++]=2,i=3;i<;++i)if (prime(i))plist[pcount++]=i;}int prime_factor(int n, int* f, int *nf) {int cnt = 0;int n2 = sqrt((double)n);for(int i = 0; n > 1 && plist[i] <= n2; ++i)if (n % plist[i] == 0) {for (nf[cnt] = 0; n % plist[i] == 0; ++nf[cnt], n /= plist[i]);f[cnt++] = plist[i];}if (n > 1) nf[cnt] = 1, f[cnt++] = n;return cnt;}/*//产生MAXN以内的所有素数//note:就是//给所有2的倍数赋初值#include <cmath>#include <iostream>using namespace std;#define MAXNunsigned int plist[],pcount;unsigned int isprime[(MAXN>>5)+1];#define setbitzero(a) (isprime[(a)>>5]&=(~(1<<((a)&31))))#define setbitone(a) (isprime[(a)>>5]|=(1<<((a)&31)))#define ISPRIME(a) (isprime[(a)>>5]&(1<<((a)&31)))void initprime(){int i,j,m;int t=(MAXN>>5)+1;for(i=0;i<t;++i)isprime[i]=;plist[0]=2;setbitone(2);setbitzero(1);m=(int)sqrt(MAXN);for(pcount=1,i=3;i<=m;i+=2)if(ISPRIME(i))for(plist[pcount++]=i,j=i<<1;j<=MAXN;j+=i)setbitzero(j);if(!(i&1))++i;for(;i<=MAXN;i+=2)if(ISPRIME(i))plist[pcount++]=i;}6. 最大公约数欧拉函数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;}二.图论_匹配1. 二分图最大匹配(hungary邻接表形式)//二分图最大匹配,hungary算法,邻接表形式,复杂度O(m*e)//返回最大匹配数,传入二分图大小m,n和邻接表list(只需一边) //match1,match2返回一个最大匹配,未匹配顶点match值为-1 #include <string.h>#define MAXN 310#define _clr(x) memset(x,0xff,sizeof(int)*MAXN)struct edge_t{int from,to;edge_t* next;};int hungary(int m,int n,edge_t* list[],int* match1,int* match2){ int s[MAXN],t[MAXN],p,q,ret=0,i,j,k;edge_t* e;for(_clr(match1),_clr(match2),i=0;i<m;ret+=(match1[i++]>=0))for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)for (e=list[k=s[p]];e&&match1[i]<0;e=e->next)if (t[j=e->to]<0){s[++q]=match2[j],t[j]=k;if (s[q]<0)for (p=j;p>=0;j=p)match2[j]=k=t[j],p=match1[k],match1[k]=j;}return ret; }2. 二分图最大匹配(hungary邻接表形式,邻接阵接口)//二分图最大匹配,hungary算法,邻接表形式,邻接阵接口,复杂度O(m*e)s//返回最大匹配数,传入二分图大小m,n和邻接阵//match1,match2返回一个最大匹配,未匹配顶点match值为-1 #include <string.h>#include <vector>#define MAXN 310#define _clr(x) memset(x,0xff,sizeof(int)*MAXN)int hungary(int m,int n,int mat[][MAXN],int* match1,int*match2){int s[MAXN],t[MAXN],p,q,ret=0,i,j,k,r;vector<int> e[MAXN];//生成邻接表(只需一边)for(i=0;i<m;++i)for(j=0;j<n;++j)if (mat[i][j]) e[i].push_back(j);for(_clr(match1),_clr(match2),i=0;i<m;ret+=(match1[i++]>=0))for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)for(r=0,k=s[p];r<e[k].size()&&match1[i]<0;++r)if (t[j=e[k][r]]<0){s[++q]=match2[j],t[j]=k;if (s[q]<0)for (p=j;p>=0;j=p)match2[j]=k=t[j],p=match1[k],match1[k]=j;}return ret;}3. 二分图最大匹配(hungary邻接阵形式)//二分图最大匹配,hungary算法,邻接阵形式,复杂度O(m*m*n) //返回最大匹配数,传入二分图大小m,n和邻接阵mat,非零元素表示有边//match1,match2返回一个最大匹配,未匹配顶点match值为-1 #include <string.h>#define MAXN 310#define _clr(x) memset(x,0xff,sizeof(int)*MAXN)int hungary(int m,int n,int mat[][MAXN],int* match1,int*match2){int s[MAXN],t[MAXN],p,q,ret=0,i,j,k;for(_clr(match1),_clr(match2),i=0;i<m;ret+=(match1[i++]>=0))for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)for (k=s[p],j=0;j<n&&match1[i]<0;j++)if (mat[k][j]&&t[j]<0){s[++q]=match2[j],t[j]=k;if (s[q]<0)for (p=j;p>=0;j=p)match2[j]=k=t[j],p=match1[k],match1[k]=j;}return ret;}4. 二分图最大匹配(hungary正向表形式)//二分图最大匹配,hungary算法,正向表形式,复杂度O(m*e)//返回最大匹配数,传入二分图大小m,n和正向表list,buf(只需一边)//match1,match2返回一个最大匹配,未匹配顶点match值为-1 #include <string.h>#define MAXN 310#define _clr(x) memset(x,0xff,sizeof(int)*MAXN)int hungary(int m,int n,int* list,int* buf,int* match1,int* match2){ int s[MAXN],t[MAXN],p,q,ret=0,i,j,k,l;for(_clr(match1),_clr(match2),i=0;i<m;ret+=(match1[i++]>=0))for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)for(l=list[k=s[p]];l<list[k+1]&&match1[i]<0;l++)if (t[j=buf[l]]<0){s[++q]=match2[j],t[j]=k;if (s[q]<0)for (p=j;p>=0;j=p)match2[j]=k=t[j],p=match1[k],match1[k]=j;}return ret;}5. 二分图最佳匹配(kuhn_munkras邻接阵形式)//二分图最佳匹配,kuhn munkras算法,邻接阵形式,复杂度O(m*m*n)//返回最佳匹配值,传入二分图大小m,n和邻接阵mat,表示权值//match1,match2返回一个最佳匹配,未匹配顶点match值为-1 //一定注意m<=n,否则循环无法终止//最小权匹配可将权值取相反数#include <string.h>#define MAXN 310#define inf#define _clr(x) memset(x,0xff,sizeof(int)*n)int kuhn_munkras(int m,int n,int mat[][MAXN],int* match1,int* match2){ints[MAXN],t[MAXN],l1[MAXN],l2[MAXN],p,q,ret=0,i,j,k;for (i=0;i<m;i++)for (l1[i]=-inf,j=0;j<n;j++)l1[i]=mat[i][j]>l1[i]?mat[i][j]:l1[i];for (i=0;i<n;l2[i++]=0);for (_clr(match1),_clr(match2),i=0;i<m;i++){for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)for (k=s[p],j=0;j<n&&match1[i]<0;j++)if (l1[k]+l2[j]==mat[k][j]&&t[j]<0){s[++q]=match2[j],t[j]=k;if (s[q]<0)for (p=j;p>=0;j=p)match2[j]=k=t[j],p=match1[k],match1[k]=j;}if (match1[i]<0){for (i--,p=inf,k=0;k<=q;k++)for (j=0;j<n;j++)if(t[j]<0&&l1[s[k]]+l2[j]-mat[s[k]][j]<p)p=l1[s[k]]+l2[j]-mat[s[k]][j];for (j=0;j<n;l2[j]+=t[j]<0?0:p,j++);for (k=0;k<=q;l1[s[k++]]-=p);}}for (i=0;i<m;i++)ret+=mat[i][match1[i]];return ret;}6. 一般图匹配(邻接表形式)//一般图最大匹配,邻接表形式,复杂度O(n*e)//返回匹配顶点对数,match返回匹配,未匹配顶点match值为-1 //传入图的顶点数n和邻接表list#define MAXN 100struct edge_t{int from,to;edge_t* next;};int aug(int n,edge_t* list[],int* match,int* v,int now){int t,ret=0;edge_t* e;v[now]=1;for (e=list[now];e;e=e->next)if (!v[t=e->to]){if (match[t]<0)match[now]=t,match[t]=now,ret=1;else{v[t]=1;if (aug(n,list,match,v,match[t]))match[now]=t,match[t]=now,ret=1;v[t]=0;}if (ret)break;}v[now]=0;return ret;}int graph_match(int n,edge_t* list[],int* match){int v[MAXN],i,j;for (i=0;i<n;i++)v[i]=0,match[i]=-1;for (i=0,j=n;i<n&&j>=2;)if (match[i]<0&&aug(n,list,match,v,i))i=0,j-=2;elsei++;for (i=j=0;i<n;i++)j+=(match[i]>=0);return j/2;}7. 一般图匹配(邻接表形式,邻接阵接口)//一般图最大匹配,邻接表形式,复杂度O(n*e)//返回匹配顶点对数,match返回匹配,未匹配顶点match值为-1 //传入图的顶点数n和邻接表list#include <vector>#define MAXN 100int aug(int n,vector<int> list[],int* match,int* v,int now){ int t,ret=0,r;v[now]=1;// for (e=list[now];e;e=e->next)for (r=0;r<list[now].size();++r)if (!v[t=list[now][r]]){if (match[t]<0)match[now]=t,match[t]=now,ret=1;else{v[t]=1;if (aug(n,list,match,v,match[t]))match[now]=t,match[t]=now,ret=1;v[t]=0;}if (ret)break;}v[now]=0;return ret;}int graph_match(int n,int mat[][MAXN],int* match){int v[MAXN],i,j;vector<int> list[MAXN];for (i=0;i<n;i++)for (j=0;j<n;j++)if (mat[i][j]) list[i].push_back(j);for (i=0;i<n;i++)v[i]=0,match[i]=-1;for (i=0,j=n;i<n&&j>=2;)if (match[i]<0&&aug(n,list,match,v,i))i=0,j-=2;elsei++;for (i=j=0;i<n;i++)j+=(match[i]>=0);return j/2;}8. 一般图匹配(邻接阵形式)//一般图最大匹配,邻接阵形式,复杂度O(n^3)//返回匹配顶点对数,match返回匹配,未匹配顶点match值为-1 //传入图的顶点数n和邻接阵mat#define MAXN 100int aug(int n,int mat[][MAXN],int* match,int* v,int now){ int i,ret=0;v[now]=1;for (i=0;i<n;i++)if (!v[i]&&mat[now][i]){if (match[i]<0)match[now]=i,match[i]=now,ret=1;else{v[i]=1;if (aug(n,mat,match,v,match[i]))match[now]=i,match[i]=now,ret=1;v[i]=0;}if (ret)break;}v[now]=0;return ret;}int graph_match(int n,int mat[][MAXN],int* match){int v[MAXN],i,j;for (i=0;i<n;i++)v[i]=0,match[i]=-1;for (i=0,j=n;i<n&&j>=2;)if (match[i]<0&&aug(n,mat,match,v,i))i=0,j-=2;elsei++;for (i=j=0;i<n;i++)j+=(match[i]>=0);return j/2;}9. 一般图匹配(正向表形式)//一般图最大匹配,正向表形式,复杂度O(n*e)//返回匹配顶点对数,match返回匹配,未匹配顶点match值为-1 //传入图的顶点数n和正向表list,buf#define MAXN 100int aug(int n,int* list,int* buf,int* match,int* v,int now){ int i,t,ret=0;v[now]=1;for (i=list[now];i<list[now+1];i++)if (!v[t=buf[i]]){if (match[t]<0)match[now]=t,match[t]=now,ret=1;else{v[t]=1;if (aug(n,list,buf,match,v,match[t]))match[now]=t,match[t]=now,ret=1;v[t]=0;}if (ret)break;}v[now]=0;return ret;}int graph_match(int n,int* list,int* buf,int* match){int v[MAXN],i,j;for (i=0;i<n;i++)v[i]=0,match[i]=-1;for (i=0,j=n;i<n&&j>=2;)if (match[i]<0&&aug(n,list,buf,match,v,i))i=0,j-=2;elsei++;for (i=j=0;i<n;i++)j+=(match[i]>=0);return j/2;}三.图论_生成树1. 最小生成树(kruskal邻接表形式)//无向图最小生成树,kruskal算法,邻接表形式,复杂度O(mlogm) //返回最小生成树的长度,传入图的大小n和邻接表list//可更改边权的类型,edge[][2]返回树的构造,用边集表示//如果图不连通,则对各连通分支构造最小生成树,返回总长度#include <string.h>#define MAXN 200#define inftypedef double elem_t;struct edge_t{int from,to;elem_t len;edge_t* next;};#define _ufind_run(x) for(;p[t=x];x=p[x],p[t]=(p[x]?p[x]:x))#define _run_both _ufind_run(i);_ufind_run(j)struct ufind{int p[MAXN],t;void init(){memset(p,0,sizeof(p));}void set_friend(int i,int j){_run_both;p[i]=(i==j?0:j);}int is_friend(int i,int j){_run_both;return i==j&&i;}};#define _cp(a,b) ((a).len<(b).len)struct heap_t{int a,b;elem_t len;};struct minheap{heap_t h[MAXN*MAXN];int n,p,c;void init(){n=0;}void ins(heap_t e){for(p=++n;p>1&&_cp(e,h[p>>1]);h[p]=h[p>>1],p>>=1);h[p]=e;}int del(heap_t& e){if (!n) return 0;for(e=h[p=1],c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n ]);h[p]=h[c],p=c,c<<=1);h[p]=h[n--];return 1;}};elem_t kruskal(int n,edge_t* list[],int edge[][2]){ufind u;minheap h;edge_t* t;heap_t e;elem_t ret=0;int i,m=0;u.init(),h.init();for (i=0;i<n;i++)for (t=list[i];t;t=t->next)if (i<t->to)e.a=i,e.b=t->to,e.len=t->len,h.ins(e);while (m<n-1&&h.del(e))if (!u.is_friend(e.a+1,e.b+1))edge[m][0]=e.a,edge[m][1]=e.b,ret+=e.len,u.set_friend(e.a+ 1,e.b+1);return ret;}2. 最小生成树(kruskal正向表形式)//无向图最小生成树,kruskal算法,正向表形式,复杂度O(mlogm) //返回最小生成树的长度,传入图的大小n和正向表list,buf//可更改边权的类型,edge[][2]返回树的构造,用边集表示//如果图不连通,则对各连通分支构造最小生成树,返回总长度#include <string.h>#define MAXN 200#define inftypedef double elem_t;struct edge_t{int to;elem_t len;};#define _ufind_run(x) for(;p[t=x];x=p[x],p[t]=(p[x]?p[x]:x))#define _run_both _ufind_run(i);_ufind_run(j)struct ufind{int p[MAXN],t;void init(){memset(p,0,sizeof(p));}void set_friend(int i,int j){_run_both;p[i]=(i==j?0:j);}int is_friend(int i,int j){_run_both;return i==j&&i;}};#define _cp(a,b) ((a).len<(b).len)struct heap_t{int a,b;elem_t len;};struct minheap{heap_t h[MAXN*MAXN];int n,p,c;void init(){n=0;}void ins(heap_t e){for(p=++n;p>1&&_cp(e,h[p>>1]);h[p]=h[p>>1],p>>=1);h[p]=e;}int del(heap_t& e){if (!n) return 0;for(e=h[p=1],c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n ]);h[p]=h[c],p=c,c<<=1);h[p]=h[n--];return 1;}};elem_t kruskal(int n,int* list,edge_t* buf,int edge[][2]){ ufind u;minheap h;heap_t e;elem_t ret=0;int i,j,m=0;u.init(),h.init();for (i=0;i<n;i++)for (j=list[i];j<list[i+1];j++)if (i<buf[j].to)e.a=i,e.b=buf[j].to,e.len=buf[j].len,h.ins(e);while (m<n-1&&h.del(e))if (!u.is_friend(e.a+1,e.b+1))edge[m][0]=e.a,edge[m][1]=e.b,ret+=e.len,u.set_friend(e.a+ 1,e.b+1);return ret;}3. 最小生成树(prim+binary_heap邻接表形式)//无向图最小生成树,prim算法+二分堆,邻接表形式,复杂度O(mlogm)//返回最小生成树的长度,传入图的大小n和邻接表list//可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1//必须保证图的连通的!#define MAXN 200#define inftypedef double elem_t;struct edge_t{int from,to;elem_t len;edge_t* next;};#define _cp(a,b) ((a).d<(b).d)struct heap_t{elem_t d;int v;};struct heap{heap_t h[MAXN*MAXN];int n,p,c;void init(){n=0;}void ins(heap_t e){for(p=++n;p>1&&_cp(e,h[p>>1]);h[p]=h[p>>1],p>>=1);h[p]=e;}int del(heap_t& e){if (!n) return 0;for(e=h[p=1],c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n ]);h[p]=h[c],p=c,c<<=1);h[p]=h[n--];return 1;}};elem_t prim(int n,edge_t* list[],int* pre){heap h;elem_t min[MAXN],ret=0;edge_t* t;heap_t e;int v[MAXN],i;for (i=0;i<n;i++)min[i]=inf,v[i]=0,pre[i]=-1;h.init();e.v=0,e.d=0,h.ins(e);while (h.del(e))if (!v[e.v])for (v[e.v]=1,ret+=e.d,t=list[e.v];t;t=t->next)if (!v[t->to]&&t->len<min[t->to])pre[t->to]=t->from,min[e.v=t->to]=e.d=t->len,h.ins(e);return ret;}4. 最小生成树(prim+binary_heap正向表形式)//无向图最小生成树,prim算法+二分堆,正向表形式,复杂度O(mlogm)//返回最小生成树的长度,传入图的大小n和正向表list,buf//可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1//必须保证图的连通的!#define MAXN 200#define inftypedef double elem_t;struct edge_t{int to;elem_t len;};#define _cp(a,b) ((a).d<(b).d)struct heap_t{elem_t d;int v;};struct heap{heap_t h[MAXN*MAXN];int n,p,c;void init(){n=0;}void ins(heap_t e){for(p=++n;p>1&&_cp(e,h[p>>1]);h[p]=h[p>>1],p>>=1);h[p]=e;}int del(heap_t& e){if (!n) return 0;for(e=h[p=1],c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n ]);h[p]=h[c],p=c,c<<=1);h[p]=h[n--];return 1;}};elem_t prim(int n,int* list,edge_t* buf,int* pre){heap h;heap_t e;elem_t min[MAXN],ret=0;int v[MAXN],i,j;for (i=0;i<n;i++)min[i]=inf,v[i]=0,pre[i]=-1;h.init();e.v=0,e.d=0,h.ins(e);while (h.del(e))if (!v[i=e.v])for (v[i]=1,ret+=e.d,j=list[i];j<list[i+1];j++)if(!v[buf[j].to]&&buf[j].len<min[buf[j].to])pre[buf[j].to]=i,min[e.v=buf[j].to]=e.d=buf[j].len,h.ins(e);return ret;}5. 最小生成树(prim+mapped_heap邻接表形式)//无向图最小生成树,prim算法+映射二分堆,邻接表形式,复杂度O(mlogn)//返回最小生成树的长度,传入图的大小n和邻接表list//可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1//必须保证图的连通的!#define MAXN 200#define inftypedef double elem_t;struct edge_t{int from,to;elem_t len;edge_t* next;};#define _cp(a,b) ((a)<(b))struct heap{elem_t h[MAXN+1];int ind[MAXN+1],map[MAXN+1],n,p,c;void init(){n=0;}void ins(int i,elem_t e){for(p=++n;p>1&&_cp(e,h[p>>1]);h[map[ind[p]=ind[p>>1]]=p]=h[p >>1],p>>=1);h[map[ind[p]=i]=p]=e;}int del(int i,elem_t& e){i=map[i];if (i<1||i>n) return 0;for(e=h[p=i];p>1;h[map[ind[p]=ind[p>>1]]=p]=h[p>>1],p>>=1);for(c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[map[i nd[p]=ind[c]]=p]=h[c],p=c,c<<=1);h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;}int delmin(int& i,elem_t& e){if (n<1) return 0;i=ind[1];for(e=h[p=1],c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n ]);h[map[ind[p]=ind[c]]=p]=h[c],p=c,c<<=1);h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;}};elem_t prim(int n,edge_t* list[],int* pre){heap h;elem_t min[MAXN],ret=0,e;edge_t* t;int v[MAXN],i;for (h.init(),i=0;i<n;i++)min[i]=(i?inf:0),v[i]=0,pre[i]=-1,h.ins(i,min[i]);while (h.delmin(i,e))for (v[i]=1,ret+=e,t=list[i];t;t=t->next)if (!v[t->to]&&t->len<min[t->to])pre[t->to]=t->from,h.del(t->to,e),h.ins(t->to,min[t->to]=t->l en);return ret; }6. 最小生成树(prim+mapped_heap正向表形式)//无向图最小生成树,prim算法+映射二分堆,正向表形式,复杂度O(mlogn)//返回最小生成树的长度,传入图的大小n和正向表list,buf//可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1//必须保证图的连通的!#define MAXN 200#define inftypedef double elem_t;struct edge_t{int to;elem_t len;};#define _cp(a,b) ((a)<(b))struct heap{elem_t h[MAXN+1];int ind[MAXN+1],map[MAXN+1],n,p,c;void init(){n=0;}void ins(int i,elem_t e){for(p=++n;p>1&&_cp(e,h[p>>1]);h[map[ind[p]=ind[p>>1]]=p]=h[p >>1],p>>=1);h[map[ind[p]=i]=p]=e;}int del(int i,elem_t& e){i=map[i];if (i<1||i>n) return 0;for(e=h[p=i];p>1;h[map[ind[p]=ind[p>>1]]=p]=h[p>>1],p>>=1);for(c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[map[i nd[p]=ind[c]]=p]=h[c],p=c,c<<=1);h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;}int delmin(int& i,elem_t& e){if (n<1) return 0;i=ind[1];for(e=h[p=1],c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n ]);h[map[ind[p]=ind[c]]=p]=h[c],p=c,c<<=1);h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;}};elem_t prim(int n,int* list,edge_t* buf,int* pre){heap h;elem_t min[MAXN],ret=0,e;int v[MAXN],i,j;for (h.init(),i=0;i<n;i++)min[i]=(i?inf:0),v[i]=0,pre[i]=-1,h.ins(i,min[i]);while (h.delmin(i,e))for (v[i]=1,ret+=e,j=list[i];j<list[i+1];j++)if (!v[buf[j].to]&&buf[j].len<min[buf[j].to]) pre[buf[j].to]=i,h.del(buf[j].to,e),h.ins(buf[j].to,min[buf[j].to ]=buf[j].len);return ret;}7. 最小生成树(prim邻接阵形式)//无向图最小生成树,prim算法,邻接阵形式,复杂度O(n^2)//返回最小生成树的长度,传入图的大小n和邻接阵mat,不相邻点边权inf//可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1//必须保证图的连通的!#define MAXN 200#define inftypedef double elem_t;elem_t prim(int n,elem_t mat[][MAXN],int* pre){elem_t min[MAXN],ret=0;int v[MAXN],i,j,k;for (i=0;i<n;i++)min[i]=inf,v[i]=0,pre[i]=-1;for (min[j=0]=0;j<n;j++){for (k=-1,i=0;i<n;i++)if (!v[i]&&(k==-1||min[i]<min[k]))k=i;for (v[k]=1,ret+=min[k],i=0;i<n;i++)if (!v[i]&&mat[k][i]<min[i])min[i]=mat[pre[i]=k][i];}return ret;}8. 最小树形图(邻接阵形式)//多源最小树形图,edmonds算法,邻接阵形式,复杂度O(n^3)//返回最小生成树的长度,构造失败返回负值//传入图的大小n和邻接阵mat,不相邻点边权inf//可更改边权的类型,pre[]返回树的构造,用父结点表示//传入时pre[]数组清零,用-1标出源点#include <string.h>#define MAXN 120#define inftypedef int elem_t;elem_t edmonds(int n,elem_t mat[][MAXN*2],int* pre){ elem_t ret=0;intc[MAXN*2][MAXN*2],l[MAXN*2],p[MAXN*2],m=n,t,i,j,k;for (i=0;i<n;l[i]=i,i++);do{memset(c,0,sizeof(c)),memset(p,0xff,sizeof(p));for (t=m,i=0;i<m;c[i][i]=1,i++);for (i=0;i<t;i++)if (l[i]==i&&pre[i]!=-1){for (j=0;j<m;j++)if(l[j]==j&&i!=j&&mat[j][i]<inf&&(p[i]==-1||mat[j][i]<mat[p[i]][i ]))p[i]=j;if ((pre[i]=p[i])==-1)return -1;if (c[i][p[i]]){for(j=0;j<=m;mat[j][m]=mat[m][j]=inf,j++);for (k=i;l[k]!=m;l[k]=m,k=p[k])for (j=0;j<m;j++)if (l[j]==j){if(mat[j][k]-mat[p[k]][k]<mat[j][m])mat[j][m]=mat[j][k]-mat[p[k]][k];if(mat[k][j]<mat[m][j])mat[m][j]=mat[k][j];}c[m][m]=1,l[m]=m,m++;}for (j=0;j<m;j++)if (c[i][j])for(k=p[i];k!=-1&&l[k]==k;c[k][j]=1,k=p[k]);}}while (t<m);for (;m-->n;pre[k]=pre[m])for (i=0;i<m;i++)if (l[i]==m){for (j=0;j<m;j++)if(pre[j]==m&&mat[i][j]==mat[m][j])pre[j]=i;if(mat[pre[m]][m]==mat[pre[m]][i]-mat[pre[i]][i])k=i;}for (i=0;i<n;i++)if (pre[i]!=-1)ret+=mat[pre[i]][i];return ret;}四.图论_网络流1. 上下界最大流(邻接表形式)//求上下界网络最大流,邻接表形式//返回最大流量,-1表示无可行流,flow返回每条边的流量//传入网络节点数n,容量mat,流量下界bf,源点source,汇点sink //MAXN应比最大结点数多2,无可行流返回-1时mat未复原! #define MAXN 100#define infint _max_flow(int n,int mat[][MAXN],int source,int sink,intflow[][MAXN]){int pre[MAXN],que[MAXN],d[MAXN],p,q,t,i,j,r;vector<int> e[MAXN];for (i=0;i<n;i++)for (e[i].clear(),j=0;j<n;j++)if (mat[i][j]) e[i].push_back(j),e[j].push_back(i);for (;;){for (i=0;i<n;pre[i++]=0);pre[t=source]=source+1,d[t]=inf;for (p=q=0;p<=q&&!pre[sink];t=que[p++])for (r=0;r<e[t].size();++r){i=e[t][r];if (!pre[i]&&(j=mat[t][i]-flow[t][i])) pre[que[q++]=i]=t+1,d[i]=d[t]<j?d[t]:j;else if (!pre[i]&&(j=flow[i][t]))pre[que[q++]=i]=-t-1,d[i]=d[t]<j?d[t]:j;}if (!pre[sink]) break;for (i=sink;i!=source;)if (pre[i]>0)flow[pre[i]-1][i]+=d[sink],i=pre[i]-1;elseflow[i][-pre[i]-1]-=d[sink],i=-pre[i]-1;}for (j=i=0;i<n;j+=flow[source][i++]);return j;}int limit_max_flow(int n,int mat[][MAXN],int bf[][MAXN],int source,int sink,int flow[][MAXN]){int i,j,sk,ks;if (source==sink) return inf;for(mat[n][n+1]=mat[n+1][n]=mat[n][n]=mat[n+1][n+1]=i=0;i<n;i+ +)for(mat[n][i]=mat[i][n]=mat[n+1][i]=mat[i][n+1]=j=0;j<n;j++) mat[i][j]-=bf[i][j],mat[n][i]+=bf[j][i],mat[i][n+1]+=bf[i][j];sk=mat[source][sink],ks=mat[sink][source],mat[source][sink ]=mat[sink][source]=inf;for (i=0;i<n+2;i++)for (j=0;j<n+2;flow[i][j++]=0);_max_flow(n+2,mat,n,n+1,flow);for (i=0;i<n;i++)if (flow[n][i]<mat[n][i]) return -1;flow[source][sink]=flow[sink][source]=0,mat[source][sink] =sk,mat[sink][source]=ks;_max_flow(n,mat,source,sink,flow);for (i=0;i<n;i++)for (j=0;j<n;j++)mat[i][j]+=bf[i][j],flow[i][j]+=bf[i][j];for (j=i=0;i<n;j+=flow[source][i++]);return j;}2. 上下界最大流(邻接阵形式)//求上下界网络最大流,邻接阵形式//返回最大流量,-1表示无可行流,flow返回每条边的流量//传入网络节点数n,容量mat,流量下界bf,源点source,汇点sink //MAXN应比最大结点数多2,无可行流返回-1时mat未复原! #define MAXN 100#define inf void _max_flow(int n,int mat[][MAXN],int source,int sink,int flow[][MAXN]){int pre[MAXN],que[MAXN],d[MAXN],p,q,t,i,j;for (;;){for (i=0;i<n;pre[i++]=0);pre[t=source]=source+1,d[t]=inf;for (p=q=0;p<=q&&!pre[sink];t=que[p++])for (i=0;i<n;i++)if (!pre[i]&&j=mat[t][i]-flow[t][i]) pre[que[q++]=i]=t+1,d[i]=d[t]<j?d[t]:j;else if (!pre[i]&&j=flow[i][t])pre[que[q++]=i]=-t-1,d[i]=d[t]<j?d[t]:j;if (!pre[sink]) break;for (i=sink;i!=source;)if (pre[i]>0)flow[pre[i]-1][i]+=d[sink],i=pre[i]-1;elseflow[i][-pre[i]-1]-=d[sink],i=-pre[i]-1;}}int limit_max_flow(int n,int mat[][MAXN],int bf[][MAXN],int source,int sink,int flow[][MAXN]){int i,j,sk,ks;if (source==sink) return inf;for(mat[n][n+1]=mat[n+1][n]=mat[n][n]=mat[n+1][n+1]=i=0;i<n;i+ +)for(mat[n][i]=mat[i][n]=mat[n+1][i]=mat[i][n+1]=j=0;j<n;j++) mat[i][j]-=bf[i][j],mat[n][i]+=bf[j][i],mat[i][n+1]+=bf[i][j];sk=mat[source][sink],ks=mat[sink][source],mat[source][sink ]=mat[sink][source]=inf;for (i=0;i<n+2;i++)for (j=0;j<n+2;flow[i][j++]=0);_max_flow(n+2,mat,n,n+1,flow);for (i=0;i<n;i++)if (flow[n][i]<mat[n][i]) return -1;flow[source][sink]=flow[sink][source]=0,mat[source][sink] =sk,mat[sink][source]=ks;_max_flow(n,mat,source,sink,flow);for (i=0;i<n;i++)for (j=0;j<n;j++)mat[i][j]+=bf[i][j],flow[i][j]+=bf[i][j];for (j=i=0;i<n;j+=flow[source][i++]);return j;}3. 上下界最小流(邻接表形式)//求上下界网络最小流,邻接阵形式//返回最大流量,-1表示无可行流,flow返回每条边的流量//传入网络节点数n,容量mat,流量下界bf,源点source,汇点sink //MAXN应比最大结点数多2,无可行流返回-1时mat未复原! #define MAXN 100#define inf。
ACM培训

4我们现在这个主题“搜索 ” 我们现在这个主题 “搜索”即是对状 态空间搜索:
如果按专业点的说法就是将问题求解过 程表现为从初始状态到目标状态寻找这 个路径的过程。 个路径的过程。 通俗点说, 就是在解一个问题时, 通俗点说 , 就是在解一个问题时 , 找到 一条解题的过程可以从求解的开始到问 题的结果。 题的结果。
5.A*算法
由于求解问题的过程中分枝有很多, 由于求解问题的过程中分枝有很多,主 要是求解过程中求解条件的不确定性, 要是求解过程中求解条件的不确定性, 不完备性造成的, 不完备性造成的,使得求解的路径很多 这就构成了一个图, 这就构成了一个图,我们说这个图就是 状态空间。 状态空间。 问题的求解实际上就是在这个图中找到 一条路径可以从开始到结果。 一条路径可以从开始到结果。这个寻找 的过程就是状态空间搜索。 的过程就是状态空间搜索。
6.搜索树
3. 静态最优查找树/次优查找树:考虑到上面折半查 静态最优查找树/ 找在概率问题下的效率不行, 找在概率问题下的效率不行,我们就想能不能把折半 查找二叉树中概率最大的数据放在根的位置上或者放 在离根较近的位置上?基于此,静态最优查找树/ 在离根较近的位置上?基于此,静态最优查找树/次优 查找树的思想就是在折半查找二叉树的基础上求解一 个带权(数据被查找概率)路径长度最小/近视最小的树。 个带权(数据被查找概率)路径长度最小/近视最小的树。 总体上说, 静态最优 / 总体上说 , 静态最优/ 次优查找树的时间复杂度也在 O(log2 N)数量级上( O(log2 N)数量级上(特别是在数据具有查找概率的情 况下也能保证这个效率) 况下也能保证这个效率)。
2010暑假培训 2010暑假培训
7.20~ 7.20~7.26
第一阶段主要内容
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
所以在 a[p:q-1]和 a[q+1:r]都已排好的序后,不需要执行任何计算,a[p:r]就
已排好序。 b. 用函数 maxtap()求出最大差值。 4、源程序: #include<iostream.h> #include<stdio.h> double a[1000000]; template<class Type> void swap(Type &x,Type &y) {
cout<<sn[i]<<'\n'; } 5、算法分析:
函数 count()的复杂度为 O(1),主函数调用 count(),故该
算法的时间复杂度为 O(1)。 实验二 最大间隙问题 1、问题描述:
最大间隙问题:给定 n 个实数 x1 , x2 ,... , xn,求这 n 个 数在实轴上相邻2 个数之间的最大差值。假设对任何实数的 下取整函数耗时 O(1),设计解最大间隙问题的线性时间算法。 对于给定的 n 个实数 x1 , x2 ,... , xn,编程计算它们的 最大间隙。
a. 统计从个位算起前 j 位0~9个数; b. 如果 j+1位为0,去掉第 j+1位补0个数; c. 统计第 j+1位出现1~(r-1)个数; d. 统计第 j+1位出现 r 个数。 4、源程序: #include <iostream.h> int main()
{ long int sn[10]; int i,n,c,k,s,pown; for(i=0;i<10;i++) sn[i]=0;
swap(a[low],a[mid]);
if((a[low]<a[high]&&a[mid]>a[high])||(a[low]>a[high] &&a[mid]<a[high]))
swap(a[low],a[high]); pivotkey=a[low]; int i=low; int j=high+1; while(true) { while(a[++i]<pivotkey); while(a[--j]>pivotkey); if(i>=j) break; swap(a[i],a[j]); } a[low]=a[j]; a[j]=pivotkey;
实验一 统计数字问题
实验二 最大间隙问题
实验三
众数问题
实验四
半数集问题
实验五
集合划分问题
实验六
最少硬币问题
实验七
编辑距离问题
实验八
程序存储问题
实验九
最优服务次序问题
实验十
汽车加油问题
实验十一 工作分配问题
实验十二 0-1背包问题
实验十三 最小重量机器设计问题
实验十四 最小权顶点覆盖问题
实验十五 集合相等问题
①分解:以 a[p]为基准元素将 a[p:r]划分为3段 a[p:q-1], a[q]和 a[q+1:r],使 a[p:q-1]中任何一个元素小于等于 a[p],而 a[q+1:r]中任何一个元素大于等于 a[q]。下标 q 在
划分过程中确定。 ②递归求解:通过递归调用快速排序算法分别对 a[p小顺序排列,先对这 n 个数排序,
再用后面的数减去前面的数,即可求出相邻两数的差值,找 出差值中最大的即为最大差值。
3、算法设计: a. 用快速排序算法对这 n 个数排序,快速排序算法是基于分 治策略的一个排序算
法。其基本思想是,对于输入的子数组 a[p:r],按以下三个 步骤进行排序:
cin>>n; for(k=s=0,pown=1;n>0;k++,n/=10,pown*=10) { c=n%10; for(i=0;i<10;i++) sn[i]+=c*k*(pown/10); for(i=0;i<c;i++) sn[i]+=pown; sn[c]+=1+s; sn[0] -=pown; s+=c*pown; } for(i=0;i<10;i++)
Type temp=x; x=y; y=temp; } template<class Type> int Partition(Type *a,int low,int high) {
Type pivotkey; int mid=(low+high)/2;
if((a[low]<a[mid]&&a[mid]<a[high])||(a[low]>a[mid]&& a[mid]>a[high]))
实验十六 战车问题
实验一 统计数字问题
1、问题描述:
一本书的页码从自然数1 开始顺序编码直到自然数 n。书的
页码按照通常的习惯编排,每个页码都不含多余的前导数字
0。例如,第6 页用数字6 表示,而不是06 或006 等。数字
计数问题要求对给定书的总页码 n,计算出书的全部页码中分 别用到多少次数字0,1, 2,…,9。 2、题目分析:
return j; } template<class Type> void Quicksort(Type *a,int low,int high) {
if(low<high) { int q=Partition(a,low,high); Quicksort(a,low,q-1); Quicksort(a,q+1,high); } } template<class Type> Type maxtap(Type *a,int n) { Type maxtap=0; for(int i=0;i<n-1;i++) maxtap=(a[i+1]-a[i])>maxtap?(a[i+1]-a[i]):maxtap; return maxtap; } main() {
考虑由0,1,2,…,9组成的所有 n 位数。从 n 个0到 n 个9共有 个 n 位数,在这些 n 位数中,0,1,2,…,9每个数字使用次数 相同,设为。
满足如下递归式:
由此可知,。 据此,可从低位向高位进行统计,再减去多余的0的个数即 可。 3、算法设计:
定义数组 a[10]存放0到9这10个数出现的次数,个 位为第0位,第 j 位的数字为 r。采用 while 循环从低位向高 位统计: