ACM-ICPC培训资料汇编(6)数论、组合数学分册(版本号1.0.0)
icpc 中的一些数学定理
icpc 中的一些数学定理【原创版】目录1.ICPC 的背景和意义2.ICPC 中涉及的数学定理3.数学定理在 ICPC 中的应用4.ICPC 对数学定理的启示正文一、ICPC 的背景和意义国际大学生程序设计竞赛(ICPC)是一场全球范围内的大学生计算机程序设计竞赛,旨在发现和培养优秀的计算机人才。
比赛中,参赛队员需要利用计算机编程解决一系列复杂的数学问题。
因此,熟悉和掌握一些数学定理在比赛中具有重要意义。
二、ICPC 中涉及的数学定理在 ICPC 中,涉及到的数学定理主要包括以下几类:1.组合数学定理:如排列组合、二项式定理、生成函数等。
2.几何与拓扑定理:如欧拉公式、三角形面积公式、欧拉 - 费马定理等。
3.代数与数论定理:如平方差公式、贝祖定理、费马小定理等。
4.微积分与概率定理:如微积分基本定理、概率论基本定理、大数定律等。
三、数学定理在 ICPC 中的应用在 ICPC 中,数学定理的应用主要体现在以下几个方面:1.提高算法效率:通过应用数学定理,可以简化问题,降低算法复杂度,从而提高算法效率。
2.优化算法设计:数学定理可以为算法设计提供理论依据,帮助参赛队员更好地理解问题,从而设计出更优秀的算法。
3.丰富解题思路:掌握数学定理,可以拓展参赛队员的解题思路,提高解题能力。
四、ICPC 对数学定理的启示ICPC 作为一场全球性的计算机程序设计竞赛,不仅考验着参赛队员的编程能力,还考验着他们的数学素养。
因此,通过参加 ICPC,我们可以得到以下启示:1.学以致用:学习数学定理不仅要掌握其理论知识,还要学会在实际问题中应用。
2.跨学科合作:在解决复杂问题时,需要计算机科学与其他学科的知识相互结合,发挥各自优势。
ACM-ICPC知识体系
其他数学问题
概率统计:赌博时最优决策 计算几何:平面、空间的计算 组合数学:非常非常多的稀奇古怪的问题 …………
其他
当然,作为一个出色的ACM-ICPC选手,除了 数据结构、算法、数学这些大的知识外,还应 该学习很多东西 每一个知识点都是循序渐进的,既有很简单的 小东西,也有最深奥的学术问题 代码功底是基础,至少应该熟练掌握 C/C++/Java中的一种
合理地存储数据,以满足数据的插入/删除/查 询操作的全局最优 所谓全局最优,就是要根据实际应用设计最合 理的存储结构
示例:数组和链表
回忆一下上次课的内容: 数组的特点:
内存中的连续区域 常数时间访问和写入 插入和删除比较耗时
链表的特点
在内存中分布不连续,依靠指针联系 不能随机访问 插入和删除元素为常数时间
举例
存储学生的成绩,用数组好还是链表好? 存储加油站等待加油的汽车,哪个好?
示例
实际情况中的数据结构更为复杂
论坛中的文章、跟贴、用户之间复e
所以需要更为复杂的数据结构
算法
算法的核心问题:效率 效率
时间效率 空间效率
时间和空间效率必须兼顾 首先,我们来看一个具体问题
在一个排好序的数组中查找某个值 a[20] = { 0,1,2,3,7, 8,9,10,21,22, 23,24,29,35,36, 37,38,45,47,49 } 查找该数组中是否存在:17,22,45
方法一:直接查找
int find (int t){ int i; for( i = 0; i < 20; i++){ if(a[i] == t) return 1; } return 0; }
效率分析
ACM培训第十二讲-组合数学
定理
10人中一定有4人相互认识或有3人相互不认识。
证明:在这10个人中任意挑选一个人,不妨把这个人称作p。则 其他的9个人可以分为下面的两个集合F和S。其中 F=与p相识的人的集合,S=与p不相识的人的集合 如果S中有4个(或4个以上)人,则或者这4个人(或4个人以上) 或者彼此认识,或者有两个人彼此不认识。如果有4个人彼此认 识,则结论成立。如果在S中有2人彼此不认识,则由于这两个人 都与p不认识,因此有3人彼此不认识,故定理结论成立。 如果S中最多有3个人,则由鸽笼原理知,F中至少有6个人。由定 理2.3知,F中一定有3人相互认识或有3人相互不认识。如果有3 个人彼此不认识,则定理成立。如果有3个人彼此认识,则把p加 入,就有4个彼此认识的人,故定理得证。
A2 A3 A5 A7 120 A2 A3 A5 A7 A2 A3 A2 A5 A2 A7 A3 A5 A3 A7 A5 A7 A2 A3 A5 A2 A3 A7 A2 A5 A7 A3 A5 A7 A2 A3 A5 A7
i 1
m
10
i
Ramsey定理
定理 6个人中一定有3个人相互认识或相互不认识。 证明:先考虑6个人中的任意一个人,不妨把这个人称作p。则其 他的5个人可以分为下面的两个集合F和S。其中 F=与p相识的人的集合,S=与p不相识的人的集合 由鸽笼原理知,这两个集合中至少有一个集合包含有3个人。 若F包含有3个人,则这3个人或者彼此不相识,或者有两个人彼 此相识。如果F中有3个人彼此不相识,则结论成立。如果F中有 2人相识,则由于这两个人都与p相识,因此有3人彼此相识,故 定理结论成立。 类似的,如果S包含3个人,则这3个人或者彼此相识,或者有两 个人彼此不相识。如果这3个人彼此相识,则结论成立。如果有 两个人彼此不相识,则由于这两个人都与p也不相识,因此有3个 人彼此不相识,故定理结论成立。
ACM培训材料PPT课件
}
2020/10/13
7
注意上面程序的M的好处
上面M定义为10000,这样不仅提高了效率而 且也节省了空间
如果要你把N阶乘转成2或3进制你会吗? 如:把18!转换成2进制. 如果你不会,那么你还没对那个程序M深刻
理解.
2020/10/13
8
N!末尾有多少个0
很简单,只要N!有多少个5这个因子,就有多少 个0.
进位e=0 (e=(a[1]+b[1]+e)/10) c[2]=(a[2]+b[2])%10+e=0, 百位进位e=1,依次下去,
最后把数组输出就是结果(要倒过来输出)
2020/10/13
4
对上面例子的实现
#include<stdio.h>
#include<string.h>
#define N
{
p=a[i]+b[i]+e;
c[i]=p%10;
e=p/10;
}
lc=lb;
while(e>0)
{
lc++;
c[lc]=e%10;
e/=10;
}
for(i=lc;i>=0;i--)
{
printf("%d",c[i]);
}
printf("\n");
return 0;
}
2020/10/13
5
用高精度算N阶乘
汇报人:XXXX 日期:20XX年XX月XX日
11
详细见课堂分析.
2020/10/13
9
fjnu:1743 fjnu:1185 fjnu:1307 fjnu:1191 fjnu:1158
北大ACM训练课程点
ACM/ICPC竞赛中用到的大量算法,包括:组合数学、数论、图论、计算几何、高级数据结构等。
北京大学
课程内容共八个专题,除理论知识外还包括精选例题讲解:
7.14 数据结构(一): 线段树,树状数组,二维线段树
7.15 数学题:组合数学,数论等
7.16 数据结构(二): 并查集, DFA, Trie图等
7.17 若干图论问题:最小生成树最短路强连通分量、桥和割点等
7.21 计算几何:线与线求交,线与面求交,求凸包,半平面求交等
7.22 搜索:深搜,广搜,剪枝,A*算法
7.24 动态规划
7.24 网络流算法:基本的网络流算法,Dinic算法,带上下界的网络流,最小费用
流。
ACM培训资料
ACM培训资料目录第一篇入门篇 (3)第1章新手入门 (5)1ACM国际大学生程序设计竞赛简介 (5)2ACM竞赛需要的知识 (8)3团队配合 (14)4练习、练习、再练习 (15)5对新手的一些建议 (16)第2章C++语言介绍 (22)1C++简介 (22)2变量 (23)3C++数据类型 (25)4C++操作符 (30)5数组 (35)6字符数组 (38)7字串操作函数 (41)8过程控制 (45)9C++中的函数 (54)10函数规则 (59)第3章STL简介 (61)1泛型程序设计 (61)2STL 的组成 (67)第二篇算法篇 (102)第1章基本算法 (103)1算法初步 (103)2分治算法 (115)3搜索算法 (124)4贪婪算法 (135)第2章进阶算法 (165)1数论基础 (165)2图论算法 (180)3计算几何基础 (222)第三篇实践篇 (246)第1章《多边形》 (247)第2章《灌溉问题》 (255)第3章《L GAME》 (263)第4章《NUMBER》解题报告 (271)第5章《J OBS》解题报告 (275)第6章《包裹运送》 (283)第7章《桶的摆放》 (290)第一篇入门篇练就坚实的基础,总有一天……我们可以草木皆兵!第1章新手入门1ACM国际大学生程序设计竞赛简介1.1背景与历史1970年在美国TexasA&M大学举办了首次区域竞赛,从而拉开了国际大学生程序设计竞赛的序幕。
1977年,该项竞赛被分为两个级别,即区域赛和总决赛,这便是现代ACM竞赛的开始。
在亚洲、美国、欧洲、太平洋地区均设有区域赛点。
1995至1996年,来自世界各地的一千多支高校的代表队参加了ACM区域竞赛。
ACM 大学生程序设计竞赛由美国计算机协会(ACM)举办,旨在向全世界的大学生提供一个展示和锻炼其解决问题和运用计算机能力的机会,现已成为全世界范围内历史最悠久、规模最大的大学生程序设计竞赛。
ACM必备内容(几乎全)
2 数论........................................................................................................................................... 21
2.1 最大公约数 gcd............................................................................................................21 2.2 最小公倍数 lcm............................................................................................................22
3.1 堆(最小堆)...............................................................................................................31
3.1.1 3.1.2
删除最小值元素:.......................................................................................... 31 插入元素和向上调整:.................................................................................. 32
1.5 拓扑排序.........................................................................................................................7
ACM培训计划
ACM培训计划书制作人:xxx2008/10/21一、什么是ACMACM/ICPC ( ACM International Collegiate Programming Contest)国际大学生程序设计竞,ACM/ICPC 是由国际计算机界历史悠久、颇具权威性的组织ACM (Association for Computing Machinery ,美国计算机协会) 主办的,世界上公认的规模最大、水平最高的国际大学生程序设计竞赛,其目的旨在使大学生运用计算机来充分展示自己分析问题和解决问题的能力。
该项竞赛从1970 年举办至今已历31 届,一直受到国际各知名大学的重视,并受到全世界各著名计算机公司的高度关注,在过去十几年中,APPLE 、AT&T 、MICROSOFT 和IBM 等世界著名信息企业分别担任了竞赛的赞助商。
可以说,ACM 国际大学生程序设计竞赛已成为世界各国大学生最具影响力的国际级计算机类的赛事,是广大爱好计算机编程的大学生展示才华的舞台,是著名大学计算机教育成果的直接体现,是信息企业与世界顶尖计算机人才对话的最好机会。
该项竞赛分区域预赛和国际决赛两个阶段进行,各预赛区第一名自动获得参加世界决赛的资格,世界决赛安排在每年的 3 ~ 4 月举行,而区域预赛安排在上一年的9 ~12 月在各大洲举行。
ACM/ICPC 的区域预赛是规模很大、范围很广的赛事。
仅在2003 年参加区域预赛的队伍就有来自75 个国家(地区),1411 所大学的3150 支代表队,他们分别在127 个赛场中进行比赛,以争夺全球总决赛的73 个名额,其激烈程度可想而知。
2004 年第29 届ACM/ICPC 亚洲赛区预赛共设了北京、上海、台北、高雄、汉城、德黑兰、爱媛(日本)、达卡(孟加拉国)、马尼拉、坎普尔(印度)等10 个赛站,来自亚洲各国知名高校的各个代表队进行了激烈的角逐。
中国内地从1996 年开始参加ACM/ICPC 亚洲区预赛,至今已历九届。
acmicpc代码库
ACM/ICPC代码库目录一.数论 (4)1.阶乘最后非零位 (4)2. 模线性方程(组) (5)3. 素数表 (6)4. 素数随机判定(miller_rabin) (7)5. 质因数分解 (8)6. 最大公约数欧拉函数 (9)二.图论_匹配 (10)1. 二分图最大匹配(hungary邻接表形式) (10)2. 二分图最大匹配(hungary邻接表形式,邻接阵接口) (10)3. 二分图最大匹配(hungary邻接阵形式) (11)4. 二分图最大匹配(hungary正向表形式) (11)5. 二分图最佳匹配(kuhn_munkras邻接阵形式) (12)6. 一般图匹配(邻接表形式) (13)7. 一般图匹配(邻接表形式,邻接阵接口) (14)8. 一般图匹配(邻接阵形式) (15)9. 一般图匹配(正向表形式) (16)三.图论_生成树 (17)1. 最小生成树(kruskal邻接表形式) (17)2. 最小生成树(kruskal正向表形式) (18)3. 最小生成树(prim+binary_heap邻接表形式) (19)4. 最小生成树(prim+binary_heap正向表形式) (20)5. 最小生成树(prim+mapped_heap邻接表形式) (21)6. 最小生成树(prim+mapped_heap正向表形式) (22)7. 最小生成树(prim邻接阵形式) (23)8. 最小树形图(邻接阵形式) (24)四.图论_网络流 (25)1. 上下界最大流(邻接表形式) (25)2. 上下界最大流(邻接阵形式) (26)3. 上下界最小流(邻接表形式) (28)4. 上下界最小流(邻接阵形式) (29)5. 最大流(邻接表形式) (30)6. 最大流(邻接表形式,邻接阵接口) (31)7. 最大流(邻接阵形式) (32)8. 最大流无流量(邻接阵形式) (32)9. 最小费用最大流(邻接阵形式) (33)五. 图论_最短路径 (34)1. 最短路径(单源bellman_ford邻接阵形式) (34)2. 最短路径(单源dijkstra_bfs邻接表形式) (34)3. 最短路径(单源dijkstra_bfs正向表形式) (35)4. 最短路径(单源dijkstra+binary_heap邻接表形式) (36)5. 最短路径(单源dijkstra+binary_heap正向表形式) (37)6. 最短路径(单源dijkstra+mapped_heap邻接表形式) (37)7. 最短路径(单源dijkstra+mapped_heap正向表形式) (39)8. 最短路径(单源dijkstra邻接阵形式) (40)9. 最短路径(多源floyd_warshall邻接阵形式) (40)六. 图论_连通性 (41)1. 无向图关键边(dfs邻接阵形式) (41)2. 无向图关键点(dfs邻接阵形式) (41)3. 无向图块(bfs邻接阵形式) (42)4. 无向图连通分支(bfs邻接阵形式) (43)5. 无向图连通分支(dfs邻接阵形式) (44)6. 有向图强连通分支(bfs邻接阵形式) (44)7. 有向图强连通分支(dfs邻接阵形式) (45)8. 有向图最小点基(邻接阵形式) (45)七. 图论_应用 (46)1.欧拉回路(邻接阵形式) (46)2. 前序表转化 (47)3. 树的优化算法 (47)4. 拓扑排序(邻接阵形式). (49)5. 最佳边割集 (49)6. 最佳顶点割集 (50)7. 最小边割集 (52)8. 最小顶点割集 (53)9. 最小路径覆盖 (54)八. 图论_NP搜索 (55)1. 最大团(n小于64)(faster) (55)2. 最大团 (57)九. 组合 (58)1. 排列组合生成 (58)2. 生成gray码 (60)3. 置换(polya) (60)4. 字典序全排列 (60)5. 字典序组合 (61)6. 组合公式 (61)十. 数值计算 (62)1. 定积分计算(Romberg) (62)2. 多项式求根(牛顿法) (63)3. 周期性方程(追赶法) (65)十一. 几何 (66)1. 多边形 (66)2. 多边形切割 (69)3. 浮点函数 (70)4. 几何公式 (74)5. 面积 (76)6. 球面 (77)7. 三角形 (78)8. 三维几何 (80)9. 凸包(graham) (87)10. 网格(pick) (89)11. 圆 (90)12. 整数函数 (92)13. 注意 (94)十二. 结构 (95)1. 并查集 (95)2. 并查集扩展(friend_enemy) (95)3. 堆(binary) (96)4. 堆(mapped) (96)5. 矩形切割 (97)6. 线段树 (98)7. 线段树扩展 (100)8. 线段树应用 (102)9. 子段和 (103)10. 子阵和 (103)十三. 其他 (104)1. 分数 (104)2. 矩阵 (105)3. 日期 (107)4. 线性方程组(gauss) (109)5. 线性相关 (110)十四. 应用 (111)1. joseph (111)2. N皇后构造解 (112)3. 布尔母函数 (113)4. 第k元素 (113)5. 幻方构造 (114)6. 模式匹配(kmp) (115)7. 逆序对数 (115)8. 字符串最小表示 (116)9. 最长公共单调子序列 (116)10. 最长子序列 (118)11. 最大子串匹配 (118)12. 最大子段和 (119)13. 最大子阵和 (120)一.数论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,825265,321197185int 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 2001000#define PSIZE 100000int 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<100000;++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:2863311530就是10101010101010101010101010101010//给所有2的倍数赋初值#include <cmath>#include <iostream>using namespace std;#define MAXN 100000000unsigned int plist[6000000],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]=2863311530;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 1000000000#define _clr(x) memset(x,0xff,sizeof(int)*n)int kuhn_munkras(int m,int n,int mat[][MAXN],int* match1,int* match2){int s[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 inf 1000000000typedef 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 inf 1000000000typedef 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 inf 1000000000typedef 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 inf 1000000000typedef 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 inf 1000000000typedef 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[ind[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->len);return ret;}6. 最小生成树(prim+mapped_heap正向表形式)//无向图最小生成树,prim算法+映射二分堆,正向表形式,复杂度O(mlogn)//返回最小生成树的长度,传入图的大小n和正向表list,buf//可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1//必须保证图的连通的!#define MAXN 200#define inf 1000000000typedef 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[ind[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 inf 1000000000typedef 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 inf 1000000000typedef int elem_t;elem_t edmonds(int n,elem_t mat[][MAXN*2],int* pre){elem_t ret=0;int c[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 inf 1000000000int _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,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返回每条边的流量。
ACM培训精品PPT课件
DP (Dynamic Programming) 动态编程,动 态规划
DFS (Depth First Search) 深度优先搜索
BFS (Breadth First Search) 宽度/广度优先搜 索
输入输出
%d %lld %lf自动扫描前导空格 比如:读入5个整数到A[5]
输入文件中,数的排布是这个样子
35 26 78
99
206
不管它,直接5次%d
for ( int i = 0; i < 5; i++ ) scanf(“%d”, A + i);
%lld用于输入和输出长整数(long long,64位) %lf用于输入输出double
cout<<"j="; printf("%d\n", j); } return 0; }
0
1
j=0 j=1 j=2 j=3
2 3 4 j=j=j=j=j=
j=4
输入输出
scanf
输入格式
%d %lld %c %s %lf
对每种格式搞清楚一个重要问题
是否自动跳过前导空白?
什么是空白:空格,TAB,回车
输入输出
%s 读一个字符串,自动扫描前导空白,读到 空白结束
如: abcd efgh,将读出”abcd”
%c读一个字符,但是不扫描前导空白
如何读一个非空白字符呢?
比如,读取某人的信息,其性别用M/F表示
TopBoy M ComputerScience
Kitty
ACM-ICPC培训资料汇编(7)计算几何分册(版本号1.0.0)
计算几何分册
(版本号 1.0.0)
哈尔滨理工大学 ACM-ICPC 集训队 2012 年 12 月
哈尔滨理工大学 ACM-ICPC 培训资料汇编
序
2012 年 5 月,哈尔滨理工大学承办了 ACM-ICPC 黑龙江省第七届大学生程序设计竞 赛。做为本次竞赛的主要组织者,我还是很在意本校学生是否能在此次竞赛中取得较好成 绩,毕竟这也是学校的脸面。因此,当 2011 年 10 月确定学校承办本届竞赛后,我就给齐 达拉图同学很大压力,希望他能认真训练参赛学生,严格要求受训队员。当然,齐达拉图 同学半年多的工作还是很有成效,不仅带着黄李龙、姜喜鹏、程宪庆、卢俊达等队员开发 了我校的 OJ 主站和竞赛现场版 OJ,还集体带出了几个比较像样的新队员,使得今年省赛 我校取得了很好的成绩(当然,也承蒙哈工大和哈工程关照,没有派出全部大牛来参 赛)。
第 8 章 计算几何........................................................................................................................4 8.1 基本几何运算...................................................................................................................4 8.1.1 基本原理....................................................................................................................4 8.1.2
ACM竞赛之简单数论
THANKS
感谢观看
欧拉函数及其应用
总结词
欧拉函数是一个用于描述一个数与它的正因数之间关系的函 数,它在示一个数n的正因数的个数,特别地,如果n是一 个质数,那么欧拉函数(n)的值为2。在ACM竞赛中,欧拉函 数常常用于解决一些与数的因数和因子分解相关的问题。
05
数论中的经典题目解析
最小。
数论应用
利用数论中的欧拉路径和欧拉回路 的知识,通过贪心算法和动态规划 解决最小生成树问题。
算法设计
通过数学推导和归纳,将问题转化 为数论中的数学问题,利用数论中 的结论和公式求解。
04
数论中的数学问题
费马小定理及其应用
总结词
费马小定理是数论中的一个重要定理,它提供了一种判断一个数是否为质数的 方法。
7等。
合数:一个大于1的自然 数,除了1和它本身外, 还有其他自然数能够整 除它的数。例如:4、6
、8、9等。
1既不是质数也不是合数 。
最大公约数与最小公倍数
01
最大公约数
两个或多个整数共有的最大的正 整数约数。
02
最小公倍数
两个或多个整数的最小的公倍数。
03
最大公约数与最小 公倍数的关系
两数的乘积等于它们的最大公约 数与最小公倍数的乘积。
输标02入题
中国剩余定理的基本思想是将一个线性同余方程组转 化为若干个简单的线性同余方程,然后分别求解,最 后再通过一定的方法得到原方程组的解。
01
03
中国剩余定理的应用范围很广,不仅在数论中有广泛 应用,在其他数学领域和计算机科学中也有很多应用。
04
在应用中国剩余定理时,需要先对方程组进行整理和 化简,然后选取适当的模数使得方程组满足中国剩余 定理的条件。
清华大学ACM集训队培训资料(内部使用)
清华大学ACM集训队培训资料(内部使用)一、C++基础基本知识所有的C++程序都是有函数组成的,函数又叫做子程序,且每个C++程序必须包含一个main函数,编译器(能够把源代码转换成目标代码的程序)把翻译后的目标代码和一些启动代码组合起来,生成可执行文件,main函数就是可执行文件的入口,所以,每个C++程序有且只有一个main函数。
下面我们看一个最简单C++程序。
(程序1.1)程序1.1int main(){return 0;}在这个程序中,如果缺少任何一个字符,编译器就无法将其翻译成机器代码。
此外,C++是对大小写敏感的,这就意味着,如果我将mian()函数拼为Main(),哪么,编译器在编译这段程序的时候就会出错。
编辑源文件能够提共管理程序开发的所有步骤,包括编辑的程序成为集成开发环境(integrated development evironments, IDE)。
在windows系统下,使用较为广泛的有Microsoft Visual C++、Dev-Cpp等,在UNIX系统下,有Vim、emacs、eclipes等。
这些程序都能提供一个较好的开发平台,使我们能够方便的开发一个程序,接下我们所要了解的都是标准C++,所有源代码都在Dev-cpp下编写,能够编译通过。
如果我们修改程序1.1中的main()函数的名称,将其改为Main(),那么,IDE就会给出错误信息,比如“[Linker error] undefined reference to `WinMain@16'”,因为编译器没有找到main函数。
接下来,我们来看一个经典的C++例子(程序1.2)程序1.2#include<iostream>using namespace std;int main(void){cout<<"Hello Wrold!"<<endl;return 0;}运行结果Hello World!程序说明第一行“#include<iostream>”,是一句预处理命令,相当于把“iostream”这个文件的所有内容复制到当前位置,替换该行。
C语言程序设计ACMICPC相关知识
C语言程序设计ACMICPC相关知识ACMICPC竞赛是一个多层面的比赛体系,分为区域赛、区域总决赛和全球总决赛。
每年10月至次年3月期间,各个地区会先举办区域赛,然后根据成绩晋级到区域总决赛,最终优胜者可以参加全球总决赛。
ACM竞赛的考察内容主要包括算法和数据结构。
C语言是一种广泛使用的编程语言,也是ACM竞赛中常用的编程语言之一、下面针对ACMICPC竞赛涉及的C语言程序设计相关知识进行介绍。
1. 基本语法:了解C语言的基本语法,包括变量和数据类型的声明、流程控制语句(如if、for、while等),以及函数的定义和调用。
2.数组和字符串:学会使用数组和字符串进行数据的存储和处理。
掌握C语言中对数组的初始化、遍历和常见的操作。
3.指针:指针是C语言中的重要概念。
了解指针的定义、指针与数组之间的关系,以及指针的运算和常见的应用场景。
4.结构体和联合体:掌握结构体和联合体的定义和使用。
了解如何定义自定义的数据类型,并在程序中进行操作。
5. 动态内存分配:了解动态内存分配的概念和使用方法。
熟悉C语言中的malloc和free函数,以及使用动态内存分配解决实际问题的技巧。
6.递归:熟悉递归的概念和实现方法。
了解递归的特点、递归的应用场景,以及递归与迭代之间的关系。
7.数据结构:熟悉常见的数据结构,包括栈、队列、链表、树等。
了解它们的定义、操作和使用场景,并能用C语言来实现这些数据结构。
8.排序和查找算法:掌握常见的排序和查找算法,如冒泡排序、快速排序、二分查找等。
了解它们的原理、复杂度分析和实际应用。
9. 图和图论算法:了解图的基本概念和表示方法,以及常见的图论算法,如最短路径算法(Dijkstra算法、Floyd-Warshall算法)、最小生成树算法(Prim算法、Kruskal算法)等。
熟悉这些算法的原理和应用场景,并能用C语言来实现。
10.动态规划:了解动态规划的概念和解题思路。
掌握动态规划的基本思想和常见的应用场景,能够用C语言来实现动态规划算法。
acm数论知识点总结
acm数论知识点总结1. 整除与余数整除是数论中最基本的概念之一。
如果一个整数a可以被另一个整数b整除,那么我们说b是a的一个因子,记作b|a。
如果a不能被b整除,记作b∣a。
另外,如果a除以b得到的商为q,余数为r,那么我们有a=bq+r,并且0≤r<|b|。
这里的余数r可以用来求解问题,比如判断一个数是奇数还是偶数;或者用来求解同余方程。
2. 最大公约数和最小公倍数两个整数a和b的最大公约数(Greatest Common Divisor,GCD)是能够整除a和b的最大的整数。
通常记作gcd(a, b)。
最小公倍数(Least Common Multiple,LCM)是能够被a和b整除的最小的整数。
通常记作lcm(a, b)。
最大公约数和最小公倍数可以用辗转相除法快速求解,而且它们有一些常见的性质,比如gcd(a, b)⋅lcm(a, b)=a⋅b。
3. 素数素数是指只能被1和自身整除的正整数。
素数在数论中是非常重要的,它们有许多特殊的性质。
比如任意一个整数都可以分解成若干个素数的乘积。
素数在ACM竞赛中常用于判断数字的性质,或者用于设计算法。
4. 同余同余是数论中一个重要的概念,如果两个整数a和b除以一个正整数m得到的余数相同,那么我们就说a同余b模m,记作a≡b(mod m)。
同余关系具有传递性和对称性,满足一些特殊的性质。
同余关系可以用来求解很多问题,比如求解同余方程、构造递归关系等。
5. 奇数和偶数奇数是最基本的整数,它们可以被2整除;偶数是能够被2整除的整数。
奇数和偶数在一些问题中有特殊的性质,比如奇数乘以奇数得到的是奇数,奇数加偶数得到的是奇数等。
6. 欧拉定理欧拉定理是数论中一个著名的定理,它为解决同余方程提供了一个重要的工具。
欧拉定理表明,如果正整数a和m互质(即gcd(a, m)=1),那么a的欧拉函数值为φ(m),则a^φ(m)≡1(mod m)。
欧拉定理在RSA密码算法中有重要应用。
哈理工ACM-ICPC培训资料汇编(2-8)知识结构
ACM-ICPC培训资料汇编(2-8)目录(版本号1.0.0)哈尔滨理工大学ACM-ICPC集训队2012年12月目录ACM-ICPC培训资料汇编(2)基本数据结构与算法分册第1章基本数据结构.........................................................................................错误!未定义书签。
1.1 顺序表................................................................................................错误!未定义书签。
1.2 单链表................................................................................................错误!未定义书签。
1.3 双向链表............................................................................................错误!未定义书签。
1.4 循环链表............................................................................................错误!未定义书签。
1.5 栈........................................................................................................错误!未定义书签。
1.6 队列....................................................................................................错误!未定义书签。
ACM信息汇总
ACM信息汇总⼀、ACM算法总结及刷题参考(摘⾃:)初期:⼀.基本算法:(1)枚举. (poj1753,poj2965)(2)贪⼼(poj1328,poj2109,poj2586)(3)递归和分治法.(4)递推.(5)构造法.(poj3295)(6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)⼆.图算法:(1)图的深度优先遍历和⼴度优先遍历.(2)最短路径算法(dijkstra,bellman-ford,floyd,heap+dijkstra)(poj1860,poj3259,poj1062,poj2253,poj1125,poj2240)(3)最⼩⽣成树算法(prim,kruskal)(poj1789,poj2485,poj1258,poj3026)(4)拓扑排序 (poj1094)(5)⼆分图的最⼤匹配 (匈⽛利算法) (poj3041,poj3020)(6)最⼤流的增⼴路算法(KM算法). (poj1459,poj3436)三.数据结构.(1)串 (poj1035,poj3080,poj1936)(2)排序(快排、归并排(与逆序数有关)、堆排) (poj2388,poj2299)(3)简单并查集的应⽤.(4)哈希表和⼆分查找等⾼效查找法(数的Hash,串的Hash)(poj3349,poj3274,POJ2151,poj1840,poj2002,poj2503)(5)哈夫曼树(poj3253)(6)堆(7)trie树(静态建树、动态建树) (poj2513)四.简单搜索(1)深度优先搜索 (poj2488,poj3083,poj3009,poj1321,poj2251)(2)⼴度优先搜索(poj3278,poj1426,poj3126,poj3087.poj3414)(3)简单搜索技巧和剪枝(poj2531,poj1416,poj2676,1129)五.动态规划(1)背包问题. (poj1837,poj1276)(2)型如下表的简单DP(可参考lrj的书 page149):1.E[j]=opt{D[i]+w(i,j)} (poj3267,poj1836,poj1260,poj2533)2.E[i,j]=opt{D[i-1,j]+xi,D[i,j-1]+yj,D[i-1][j-1]+zij} (最长公共⼦序列)(poj3176,poj1080,poj1159)3.C[i,j]=w[i,j]+opt{C[i,k-1]+C[k,j]}.(最优⼆分检索树问题)六.数学(1)组合数学:1.加法原理和乘法原理.2.排列组合.3.递推关系.(POJ3252,poj1850,poj1019,poj1942)(2)数论.1.素数与整除问题2.进制位.3.同余模运算.(poj2635, poj3292,poj1845,poj2115)(3)计算⽅法.1.⼆分法求解单调函数相关知识.(poj3273,poj3258,poj1905,poj3122)七.计算⼏何学.(1)⼏何公式.(2)叉积和点积的运⽤(如线段相交的判定,点到线段的距离等). (poj2031,poj1039)(3)多边型的简单算法(求⾯积)和相关判定(点在多边型内,多边型是否相交)(poj1408,poj1584)(4)凸包. (poj2187,poj1113)中级:⼀.基本算法:(1)C++的标准模版库的应⽤. (poj3096,poj3007)(2)较为复杂的模拟题的训练(poj3393,poj1472,poj3371,poj1027,poj2706)⼆.图算法:(1)差分约束系统的建⽴和求解. (poj1201,poj2983)(2)最⼩费⽤最⼤流(poj2516,poj2516,poj2195)(3)双连通分量(poj2942)(4)强连通分⽀及其缩点.(poj2186)(5)图的割边和割点(poj3352)(6)最⼩割模型、⽹络流规约(poj3308, )三.数据结构:(1)线段树. (poj2528,poj2828,poj2777,poj2886,poj2750)(2)静态⼆叉检索树. (poj2482,poj2352)(3)树状树组(poj1195,poj3321)(4)RMQ. (poj3264,poj3368)(5)并查集的⾼级应⽤. (poj1703,2492)(6)KMP算法. (poj1961,poj2406)四.搜索(1)最优化剪枝和可⾏性剪枝(2)搜索的技巧和优化 (poj3411,poj1724)(3)记忆化搜索(poj3373,poj1691)五.动态规划(1)较为复杂的动态规划(如动态规划解特别的施⾏商问题等)(poj1191,poj1054,poj3280,poj2029,poj2948,poj1925,poj3034)(2)记录状态的动态规划. (POJ3254,poj2411,poj1185)(3)树型动态规划(poj2057,poj1947,poj2486,poj3140)六.数学(1)组合数学:1.容斥原理.2.抽屉原理.3.置换群与Polya定理(poj1286,poj2409,poj3270,poj1026).4.递推关系和母函数.(2)数学.1.⾼斯消元法(poj2947,poj1487, poj2065,poj1166,poj1222)2.概率问题. (poj3071,poj3440)3.GCD、扩展的欧⼏⾥德(中国剩余定理) (poj3101)(3)计算⽅法.1.0/1分数规划. (poj2976)2.三分法求解单峰(单⾕)的极值.3.矩阵法(poj3150,poj3422,poj3070)4.迭代逼近(poj3301)(4)随机化算法(poj3318,poj2454)(5)杂题.(poj1870,poj3296,poj3286,poj1095)七.计算⼏何学:(1)坐标离散化.(2)扫描线算法(例如求矩形的⾯积和周长并,常和线段树或堆⼀起使⽤).(poj1765,poj1177,poj1151,poj3277,poj2280,poj3004)(3)多边形的内核(半平⾯交)(poj3130,poj3335)(4)⼏何⼯具的综合应⽤.(poj1819,poj1066,poj2043,poj3227,poj2165,poj3429)⾼级:⼀.基本算法要求:(1)代码快速写成,精简但不失风格(poj2525,poj1684,poj1421,poj1048,poj2050,poj3306)(2)保证正确性和⾼效性. poj3434⼆.图算法:(1)度限制最⼩⽣成树和第K最短路. (poj1639)(2)最短路,最⼩⽣成树,⼆分图,最⼤流问题的相关理论(主要是模型建⽴和求解)(poj3155, poj2112,poj1966,poj3281,poj1087,poj2289,poj3216,poj2446(3)最优⽐率⽣成树. (poj2728)(4)最⼩树形图(poj3164)(5)次⼩⽣成树.(6)⽆向图、有向图的最⼩环三.数据结构.(1)trie图的建⽴和应⽤. (poj2778)(2)LCA和RMQ问题(LCA(最近公共祖先问题) 有离线算法(并查集+dfs) 和在线算法(RMQ+dfs)).(poj1330)(3)双端队列和它的应⽤(维护⼀个单调的队列,常常在动态规划中起到优化状态转移的⽬的). (poj2823)(4)左偏树(可合并堆).(5)后缀树(⾮常有⽤的数据结构,也是赛区考题的热点).(poj3415,poj3294)四.搜索(1)较⿇烦的搜索题⽬训练(poj1069,poj3322,poj1475,poj1924,poj2049,poj3426)(2)⼴搜的状态优化:利⽤M进制数存储状态、转化为串⽤hash表判重、按位压缩存储状态、双向⼴搜、A*算法.(poj1768,poj1184,poj1872,poj1324,poj2046,poj1482)(3)深搜的优化:尽量⽤位运算、⼀定要加剪枝、函数参数尽可能少、层数不易过⼤、可以考虑双向搜索或者是轮换搜索、IDA*算法. (poj3131,poj2870,poj2286)五.动态规划(1)需要⽤数据结构优化的动态规划.(poj2754,poj3378,poj3017)(2)四边形不等式理论.(3)较难的状态DP(poj3133)六.数学(1)组合数学.1.MoBius反演(poj2888,poj2154)2.偏序关系理论.(2)博奕论.1.极⼤极⼩过程(poj3317,poj1085)2.Nim问题.七.计算⼏何学.(1)半平⾯求交(poj3384,poj2540)(2)可视图的建⽴(poj2966)(3)点集最⼩圆覆盖.(4)对踵点(poj2079)⼋.综合题.(poj3109,poj1478,poj1462,poj2729,poj2048,poj3336,poj3315,poj2148,poj1263)补充:Dp状态设计与⽅程总结1.不完全状态记录<1>青蛙过河问题<2>利⽤区间dp2.背包类问题<1> 0-1背包,经典问题<2>⽆限背包,经典问题<3>判定性背包问题<4>带附属关系的背包问题<5> + -1背包问题<6>双背包求最优值<7>构造三⾓形问题<8>带上下界限制的背包问题(012背包)3.线性的动态规划问题<1>积⽊游戏问题<2>决⽃(判定性问题)<3>圆的最⼤多边形问题<4>统计单词个数问题<5>棋盘分割<6>⽇程安排问题<7>最⼩逼近问题(求出两数之⽐最接近某数/两数之和等于某数等等)<8>⽅块消除游戏(某区间可以连续消去求最⼤效益)<9>资源分配问题<10>数字三⾓形问题<11>漂亮的打印<12>邮局问题与构造答案<13>最⾼积⽊问题<14>两段连续和最⼤<15>2次幂和问题<16>N个数的最⼤M段⼦段和<17>交叉最⼤数问题4.判定性问题的dp(如判定整除、判定可达性等)<1>模K问题的dp<2>特殊的模K问题,求最⼤(最⼩)模K的数<3>变换数问题5.单调性优化的动态规划<1>1-SUM问题<2>2-SUM问题<3>序列划分问题(单调队列优化)6.剖分问题(多边形剖分/⽯⼦合并/圆的剖分/乘积最⼤)<1>凸多边形的三⾓剖分问题<2>乘积最⼤问题<3>多边形游戏(多边形边上是操作符,顶点有权值)<4>⽯⼦合并(N^3/N^2/NLogN各种优化)7.贪⼼的动态规划<1>最优装载问题<2>部分背包问题<3>乘船问题<4>贪⼼策略<5>双机调度问题Johnson算法8.状态dp<1>⽜仔射击问题(博弈类)<2>哈密顿路径的状态dp<3>两⽀点天平平衡问题<4>⼀个有向图的最接近⼆部图9.树型dp<1>完美服务器问题(每个节点有3种状态)<2>⼩胖守皇宫问题<3>⽹络收费问题<4>树中漫游问题<5>树上的博弈<6>树的最⼤独⽴集问题<7>树的最⼤平衡值问题<8>构造树的最⼩环⼆、ACM⼤赛准备(经验1)(摘⾃:)ACM常⽤算法及练习第⼀阶段:练经典常⽤算法,下⾯的每个算法给我打上⼗到⼆⼗遍,同时⾃⼰精简代码,因为太常⽤,所以要练到写时不⽤想,10-15分钟内打完,甚⾄关掉显⽰器都可以把程序打出来.1.最短路(Floyd、Dijstra,BellmanFord)2.(先写个prim,kruscal要⽤并查集,不好写)3.⼤数(⾼精度)加减乘除4.⼆分查找. (代码可在五⾏以内)5.叉乘、判线段相交、然后写个凸包.6.BFS、DFS,同时熟练(要熟,要灵活,代码要简)7.数学上的有:辗转相除(两⾏内),线段交点、多⾓形⾯积公式.8. 调⽤系统的qsort, 技巧很多,慢慢掌握.9. 任意进制间的转换第⼆阶段:练习复杂⼀点,但也较常⽤的算法。
ACM资料
最优比率生成树
0/1分数规划
度限制生成树
连通性问题
强大的DFS算法
无向图连通性
割点
割边
二连通分支
有向图连通性
强连通分支
2-SAT
最小点基
有向无环图
拓扑排序
有向无环图与动态规划的关系
二分图匹配问题
一般图问题与二分图问题的转换思路
组合数学
解决组合数学问题时常用的思想
逼近
递推 / 动态规划
概率问题
Polya定理
计算几何 / 解析几何
计算几何的核心:叉积 / 面积
解析几何的主力:复数
基本形
点
直线,线段
多边形
凸多边形 / 凸包
凸包算法的引进,卷包裹法
数论计算
求N的约数个数
求phi(N)
求约数和
快速数论变换
……
素数问题
概率判素算法
概率因子分解
数据结构
组织结构
二叉堆
左偏树
二项树
胜者树
跳跃表
样式图标
斜堆
reap
统计结构
树状数组
虚二叉树
线段树
8. 调用系统的qsort, 技巧很多,慢慢掌握.
9. 任意进制间的转换
第二阶段:
练习复杂一点,但也较常用的算法。
如:
1. 二分图匹配(匈牙利),最小路径覆盖
2. 网络流,最小费用流。
3. 线段树.
4. 并查集。
5. 熟悉动态规划的各个典型:LCS、最长递增子串、三角剖分、记忆化dp
ACM-ICPC培训资料汇编:博弈
ACM-ICPC培训资料汇编:博弈《ACMICPC 培训资料汇编:博弈》在计算机科学和数学的交叉领域中,博弈论是一个引人入胜且具有重要应用价值的研究方向。
对于参加 ACMICPC(国际大学生程序设计竞赛)的选手来说,掌握博弈相关的知识和技巧是提升竞赛能力的关键之一。
首先,让我们来理解一下什么是博弈。
简单来说,博弈就是指在一定的规则下,多个参与者进行策略选择,以达到各自的目标。
在这个过程中,参与者的决策会相互影响,最终的结果取决于所有人的选择。
博弈论中有许多经典的模型和问题,比如“囚徒困境”。
在这个模型中,两个犯罪嫌疑人被分别审讯,如果两人都保持沉默(合作),那么他们都将受到较轻的惩罚;如果一人坦白而另一人沉默(背叛),坦白者将获得从轻处罚,沉默者将受到重罚;如果两人都坦白,那么他们都将受到较重的惩罚。
在这种情况下,从个体理性的角度出发,坦白似乎是最优选择,但从整体来看,两人都保持沉默才是最优结果。
这个例子展示了个体利益与集体利益之间的冲突,以及在博弈中如何做出决策。
再比如“Nim 游戏”,这是一个非常经典的博弈问题。
假设有若干堆石子,两个玩家轮流从其中一堆中取走任意数量的石子,最后取完石子的玩家获胜。
通过对这个游戏的分析,我们可以找到获胜的策略。
在ACMICPC 竞赛中,经常会遇到需要运用博弈思想来解决的问题。
那么,如何培养解决这类问题的能力呢?第一步,要熟悉常见的博弈模型和策略。
这就像是学习数学公式一样,只有记住了常见的模型和对应的策略,才能在遇到问题时迅速找到解题的思路。
例如,“巴什博弈”“威佐夫博弈”等,都有其特定的规律和解题方法。
第二步,要善于分析问题,将实际问题转化为已知的博弈模型。
这需要我们对问题进行深入的思考,找出其中的关键要素和规则,然后与所学的模型进行对比和匹配。
第三步,多做练习。
通过大量的练习题,我们可以加深对博弈知识的理解,提高运用策略的熟练程度。
在练习的过程中,要注意总结经验,分析自己解题过程中的错误和不足之处,不断改进。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
ACM-ICPC培训资料汇编(6)数论、组合数学分册(版本号1.0.0)哈尔滨理工大学ACM-ICPC集训队2012年12月序2012年5月,哈尔滨理工大学承办了ACM-ICPC黑龙江省第七届大学生程序设计竞赛。
做为本次竞赛的主要组织者,我还是很在意本校学生是否能在此次竞赛中取得较好成绩,毕竟这也是学校的脸面。
因此,当2011年10月确定学校承办本届竞赛后,我就给齐达拉图同学很大压力,希望他能认真训练参赛学生,严格要求受训队员。
当然,齐达拉图同学半年多的工作还是很有成效,不仅带着黄李龙、姜喜鹏、程宪庆、卢俊达等队员开发了我校的OJ主站和竞赛现场版OJ,还集体带出了几个比较像样的新队员,使得今年省赛我校取得了很好的成绩(当然,也承蒙哈工大和哈工程关照,没有派出全部大牛来参赛)。
在2011年9月之前,我对ACM-ICPC关心甚少。
但是,我注意到我校队员学习、训练没有统一的资料,也没有按照竞赛所需知识体系全面系统培训新队员。
2011-2012年度的学生教练们做了一个较详细的培训计划,每周都会给2011级新队员上课,也会对老队员进行训练,辛辛苦苦忙活了一年——但是这些知识是根据他们个人所掌握情况来给新生讲解的,新生也是杂七杂八看些资料和做题。
在培训的规范性上欠缺很多,当然这个责任不在学生教练。
2011年9月,我曾给老队员提出编写培训资料这个任务,一是老队员人数少,有的还要去百度等企业实习;二是老队员要开发、改造OJ;三是培训新队员也很耗费精力,因此这项工作虽很重要,但却不是那时最迫切的事情,只好被搁置下来。
2012年8月底,2012级新生满怀梦想和憧憬来到学校,部分同学也被ACM-ICPC深深吸引。
面对这个新群体的培训,如何提高效率和质量这个老问题又浮现出来。
市面现在已经有了各种各样的ACM-ICPC培训教材,主要算法和解题思路都有了广泛深入的分析和讨论。
同时,互联网博客、BBS等中也隐藏着诸多大牛对某些算法的精彩论述和参赛感悟。
我想,做一个资料汇编,采撷各家言论之精要,对新生学习应该会有较大帮助,至少一可以减少他们上网盲目搜索的时间,二可以给他们构造一个相对完整的知识体系。
感谢ACM-ICPC先辈们作出的杰出工作和贡献,使得我们这些后继者们可以站在巨人的肩膀上前行。
感谢校集训队各位队员的无私、真诚和抱负的崇高使命感、责任感,能够任劳任怨、以苦为乐的做好这件我校的开创性工作。
唐远新 2012年10月编写说明本资料为哈尔滨理工大学ACM-ICPC集训队自编自用的内部资料,不作为商业销售目的,也不用于商业培训,因此请各参与学习的同学不要外传。
本分册大纲由黄李龙编写,内容由曹振海、陈禹等分别编写和校核。
本分册内容大部分采编自各OJ、互联网和部分书籍。
在此,对所有引用文献和试题的原作者表示诚挚的谢意!由于时间仓促,本资料难免存在表述不当和错误之处,格式也不是很规范,请各位同学对发现的错误或不当之处向acm@邮箱反馈,以便尽快完善本文档。
在此对各位同学的积极参与表示感谢!哈尔滨理工大学在线评测系统(Hrbust-OJ)网址:,欢迎各位同学积极参与AC。
国内部分知名OJ:杭州电子科技大学:北京大学:浙江大学:以下百度空间列出了比较全的国内外知名OJ:/leo_xxx/item/6719a5ffe25755713c198b50哈尔滨理工大学ACM-ICPC集训队2012年12月目录序 (I)编写说明 (II)第6章数论 (6)6.1 欧几里德算法 (6)6.1.1 基本原理 (6)6.1.2 解题思路 (6)6.1.3 模板代码 (6)6.1.4 经典题目 (6)6.2 扩展欧几里德算法 (8)6.2.1 基本原理 (8)6.2.2 解题思路 (8)6.2.3 模板代码 (8)6.2.4 经典题目 (9)6.2.5 扩展变型 (12)6.3 筛素数 (12)6.3.1 基本原理 (12)6.3.2 解题思路 (12)6.3.3 模板代码 (12)6.3.4 经典题目 (13)6.4 模线性方程 (14)6.4.1 基本原理 (15)6.4.2 解题思路 (15)6.4.3 模板代码 (15)6.4.4 经典题目 (15)6.4.5 扩展变型 (16)6.5 求解线性同余方程组 (16)6.5.1 基本原理 (16)6.5.2 解题思路 (17)6.5.3 模板代码 (17)6.5.4 经典题目 (17)6.5.5 扩展变型 (19)6.6 随机素数测试(Miller-Rabin) (19)6.6.1 基本原理 (19)6.6.2 解题思路 (19)6.6.3 模板代码 (19)6.6.4 经典题目 (20)6.7 素因子快速分解 (21)6.7.1 基本原理 (21)6.7.2 解题思路 (21)6.7.3 模板代码 (21)6.7.4 经典题目 (22)6.7.5 扩展变型 (24)6.8 整数因子分解算法(Pollard-Rho) (24)6.8.1 基本原理 (24)6.8.2 解题思路 (24)6.8.3 模板代码 (25)6.8.4 经典题目 (25)6.8.5 扩展变型 (28)6.9 欧拉函数 (28)6.9.1 基本原理 (28)6.9.2 解题思路 (28)6.9.3 模板代码 (28)6.9.4 经典题目 (28)6.9.5 扩展变型 (29)6.10 高斯消元 (29)6.10.1 基本原理 (29)6.10.2 解题思路 (29)6.10.3 模板代码 (29)6.10.4 经典题目 (32)6.10.5 扩展变型 (36)第7章组合数学 (37)7.1 母函数 (37)7.1.1 基本原理 (37)7.1.2 解题思路 (37)7.1.3 模板代码 (38)7.1.4 经典题目 (38)7.1.5 扩展变型 (39)7.2 置换群 (39)7.2.1 基本原理 (39)7.2.2 解题思路 (40)7.2.3 模板代码 (40)7.2.4 经典题目 (40)7.2.5 扩展变型 (42)7.3 排列组合 (42)7.3.1 基本原理 (42)7.3.2 解题思路 (43)7.3.3 模板代码 (43)7.3.4 经典题目 (43)7.4 卡塔兰数(Catalan) (45)7.4.1 基本原理 (45)7.4.2 解题思路 (45)7.4.3 模板代码 (46)7.4.4 经典题目 (46)7.5 容斥原理 (47)7.5.1 基本原理 (47)7.5.2 解题思路 (47)7.5.3 模板代码 (47)7.5.4 经典题目 (47)7.6 Burnside定理 (50)7.6.1 基本原理 (50)7.6.2 解题思路 (51)7.6.3 模板代码 (51)7.6.4 经典题目 (52)7.7 Polya计数 (55)7.7.1 基本原理 (55)7.7.2 解题思路 (55)7.7.3 模板代码 (55)7.7.4 经典题目 (55)第6章数论6.1欧几里德算法参考文献:《ACM—ICPC程序设计系列<数论及应用>》——哈尔滨工业大学出版社《初等数论》第二版(潘承洞,潘承彪著)北京大学出版社最大公约数-百度百科扩展阅读:编写:曹振海校核:陈禹6.1.1基本原理欧几里得算法又称为辗转相除法,设两个数a,b则a,b的最大公约gcd(a,b)=gcd(b,a%b) 不妨设a>=b,c=gcd(a,b),a=kc,b=jc,则k,j互素(否则c不是a,b的最大公约数),则设r=a%b则a=mb+r,则r=a-mb=kc-mjc=(k-mj)c,因为k,j互素,则k-mj与j互素gcd(a,b)=gcd(b,a%b)6.1.2解题思路一般很少有题目只要求最大公约数,但是通常很多题会用到求最大公约数的过程,比如判断两个数是否互素(最大公约数为1),这个时候欧几里得算法暨辗转相除法就变成了很得力的工具,因为每一步都是取模,保证了数据减小的速度特别快。
能够在很短的时间内求出两个数的最大公约数。
6.1.3模板代码//非递归版,C语言实现int gcd(int a,int b) {if(!a)return b;int c;while(b){c=b;b=a%b;a=c;}return a;}//递归版,C语言实现int gcd(int a,int b) {if(b==0)return a;return gcd(b,a%b);}6.1.4经典题目6.1.4.1题目11.题目出处/来源哈理工OJ-1328 相等的最小公倍数2.题目描述定义An为1,2,…,n的最小公倍数,例如,A1=1,A2=2,A3=6,A4=12,A5=60,A6=60。
请你判断对于给出的任意整数n,An是否等于An–1。
如果An等于An-1则输出YES否则输出NO。
3.分析由最小公倍数的定义我们可以知道,如果An=An-1则An-1可以被n整除,首先,对于一个数n如果是素数,那么An不等于An-1,其次,我们分析n,如果对于小于n的每一对因子即n=a*b(a<n且b<n),如果a,b不互素,那么gcd(a,b)>1,则lcm(a,b)=n/gcd(a,b)<n(lcm 表示最小公倍数),那么很显然,如果n的每一对因子都是不互素的,则n不能整除An-1,否则可以整除An-1,因为n的因子肯定小于等于n-1,所以其每一对因子的最小公倍数肯定可以整除An-1,所以这道题就0变成了判断n是否有互素的一对因子,所以我们只要枚举n 的每一对因子,然后计算其最大公约数是否为1,如果有一对互素的因子则输出YES,否则输出NO4.代码(包含必要注释,采用最适宜阅读的Courier New字体,小五号,间距为固定值12磅)#include<stdio.h>#include<math.h>#include<string.h>int gcd(int a,int b)//求最大公约数部分{if(b==0)return a;return gcd(b,a%b);}int main(){int n;int t;int i,j;scanf("%d",&t);while(t--){bool p=true;scanf("%d",&n);if(n==2)//特殊情况的判断{printf("NO\n");continue;}int temp=(int)sqrt((double)n);for(i=2;i<=temp;i++)//判断n是否是素数{if(n%i==0)break;}if(i==temp+1)//是素数直接输出NO{printf("NO\n");continue;}for(i=2;i<=temp;i++)//枚举n的每一对因子是否互素{if(n%i==0){int q=n/i;if(gcd(q,i)==1){p=false;break;}}}if(p)printf("NO\n");elseprintf("YES\n");}return 0;}5.思考与扩展:在辗转相除法执行之前是否一定要保证a>=b,为什么?6.2扩展欧几里德算法参考文献:扩展欧几里得-百度百科扩展欧几里得解线性方程扩展阅读:编写:曹振海校核:陈禹6.2.1基本原理设a和b不全为0,则存在整数x,y使得gcd(a,b)=xa+yb对于辗转相除法的最后一项此时b=0,则gcd(a,b)=1*a+0*b,因为gcd(a,b)=gcd(b,a%b)则有x*a+y*b=x1*b+y1*(a%b) 将等式右边变形,b*x1+(a%b)*y1=b*x1+(a-(a/b)*b)*y1=a*y1+b*(x1-(a/b)*y1)则,x=y1,y=x1-(a/b)*y1则可由后向前迭代得到x,y6.2.2解题思路对于扩展欧几里德定理的题,一般都需要进行一定的推导之后得到一个形式为xa+yb=c的方程,然后根据c确定解是否存在,如果c可以被gcd(a,b)整除,那么方程有解,否则方程无解。