青少年编程知识记录 codecoming

【数论】常见的距离度量方法

一、欧式距离欧式距离(Eucliden Metric,也是欧几里得度量)是一个通常采用的距离定义,旨在m维空间中两个点之间的真实距离,或者向量的自然长度(即该点到原点距离)。在二维和三维空间中的欧氏距离就是两点之间的实际距离。例如:对于二维平面上的两点p(x1,y1)与p(x2,y2)间的欧式距离公式为:同理,对于三维平面上两点p(x1,y1,z1)与p(x2,y2,z2)间的欧式距离公式为:欧式距离是距离算法中最常用的方式,日常生活中的大部分距离都可以通过欧式距离进行计算。二、余弦相似度余弦相
作者:亿万年的星光 分类:C++知识 浏览:

【数论】组合数学—容斥原理

  1. 概念

计数时,必须注意没有重复,没有遗漏。为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理

     2.举例

(1)如果被计数的事物有A,B两类,那么,A类和B类元素个数总和=A类元素个数+B类元素个数-即使A类又是B类元素个数。

那么公式就是:

             |A∪B|  = |A| + |B| - |A∩B| 

可以用下面的图表示(也叫韦恩图):



U表示全集(整个集合),A表示符合A类的数量,B表示符合B类的数量,I表示既不符合A也不符合B的数量,AB表示既符合A也符合B的数量,则U-I=A+B-AB。

(2)如果被计数的事物有A、B、C三类,那么,A类和B类和C类元素个数总和= A类元素个数+ B类元素个数+C类元素个数-既是A类又是B类的元素个数-既是A类又是C类的元素个数-既是B类又是C类的元素个数+既是A类又是B类而且是C类的元素个数。

            |A∪B∪C|  = |A| + |B| + |C|  - |A∩B| -  |B∩C| - | C∩A | + |A∩B∩C|

可以用下面的图表示:



U表示整个大集合,A表示符合A类的数量,B表示符合B类的数量,C表示符合C类的数量,I表示既不符合A也不符合B还不符合C的数量,AB表示既符合A也符合B的数量,BC表是同时符合B和C的数量,AC表示既符合A也符合C的数量,ABC表示同时符合A、B、C的数量。

根据容斥原理的定义,先不考虑重叠,把某内容的所有对象数目先计算出来(即A+B+C);再剔除重复计算的数目,AB这部分被计算了两次,也就是重复了一次,要剪掉,同理BC,AC也要个减掉一次;

那ABC呢?在A+B+C中我们把ABC统计了三次,所以理论上需要减掉两次,但是ABC同时又在AB、AC、BC中,也就是说我们减去AB的时候已经减了一次ABC,减去BC的时候又减了一次ABC,减AC的时候再一次减掉了ABC,即ABC总共减了三次。所以就需要额外再加回来一次。

那么等量关系就变成了U-I=A+B+C-AB-AC-BC+ABC

    3.例题

(1)为了发展体育运动,学校这学期开了体育兴趣课,学生需要从篮球和足球中选,允许两个同时选或同时不选。一个班级有50人,选了篮球的有32人,选了足球的有21人,两种都选了的有17人。问:有多少同学两种都没选。

    

如上图所示,篮球32人和足球21人,用总数50减去篮球再减去足球,中间重叠的部分被减了两次,所以再加一个中间重叠部分。50-32-21+17=14人。





(2)某校六⑴班有学生55人,每人在暑假里都参加体育训练队,其中参加足球队的有22人,参加排球队的有23人,参加游泳队的有24人,足球、排球都参加的有11人,足球、游泳都参加的有10人,排球、游泳都参加的有9人,问:三项都参加的有多少人?

我们假设足球队是A,排球队是B,游泳队是C。那么根据公式  |A∪B∪C|  = |A| + |B| + |C|  - |A∩B| -  |B∩C| - | C∩A | + |A∩B∩C| 可以得出。

    55 = 22+23+24-11-10-9 +  |A∩B∩C| 。该式子计算得:16



(3) 
  假设班里有50名学生,每个人都必须选修一门运动科目,选修篮球的有15人,选修足球的有20人,选修乒乓球的有30人,同时选修篮球和足球的有10人,同时选修乒乓球和足球的有18人,同时选修篮球和乒乓球的有12人,问选修了三门科目的有多少人?





    根据上面的公式,可以15+20+30-10-18-12 + x =50。得x=25。

    思考一下?





 4.常见题目类型:

(1)排列问题:

    由0到9的数字组成排列,要求第一个数大于1,最后一个数小于8,一共有多少种排列?

(2)序列问题:

长度为n的由数字0,1,2组成的序列,要求每个数字至少出现1次,这样的序列有多少种?

(3)方程组整数解问题

   给出一个方程:x1+x2+x3+x4+x5+x6=20, 对于每个 0<=xi<=8,求解这个方程组有多少组解。

(3)区间内互素个数

       给出整数n和r。求区间[1;r]中与n互素的数的个数。

(4)至少一个被整除问题

       给出n个整数ai和整数r。求在区间[1;r]中,至少能被一个ai整除的数有多少。

(5)匹配字符串个数问题

       给出n个匹配串,它们长度相同,其中有一些’?’表示待匹配的字母。然后给出一个整数k,求能正好匹配k个匹配串的字符串的个数。更进一步,求至少匹配k个匹配串的字符串的个数。

(6)路径数据问题

    在一个的n*m方格阵中,有k个格子是不可穿越的墙。一开始在格子(1,1)(最左下角的格子)中有一个机器人。这个机器人只能向上或向右行进,最后它将到达位于格子(n,m)的笼子里,其间不能经过障碍物格子。求一共有多少种路线可以到达终点。

(7)数组四元组问题

       给出n个数a1,a2,a3....an,从其中选出4个数,使它们的最大公约数为1,问总共有多少中取法。

(8)和睦数三元组个数问题

(9)错排问题

作者:亿万年的星光 分类:C++知识 浏览:

【题解】组合数学

一、排列与组合口诀:有序排列,无序组合,分类相加,分步相乘。1.排列数公式:表示的含义是从n个数中选出m个进行排队,有多少种不同的排法。从n个不同的元素中任取m(m≤n)个元素的所有排列的个数,叫做从n个不同的元素中取出m(m≤n)个元素的排列数。排列与元素的顺序有关,组合与顺序无关。排列数公式:A(n,m) = n*(n-1)*...*(n-m+1)=n!/(n-m)!排列数公式中总共有m项乘积。常见的题目类别:捆绑法插空法代码模板(递归法):// 计算阶乘 int fa
作者:亿万年的星光 分类:C++知识 浏览:

【算法】扩展欧几里得算法

一、欧几里得算法

我们前面学过求最大公约数的算法:欧几里得算法(又叫辗转相除法) ,一般缩写是gcd,在C++中经常写成如下形式:

int gcd(int a,int b)     {        if(a%b==0)           return b;       else           return gcd(b,a%b);   }

原理就是代码中比较核心的 gcd(b,a%b),这个定理用文字描述就是:

用a除以b(这里是a>b,当然,在程序编程中,求两个数的最大公约数,可以不限a和b的大小,a<b也就是多一次循环)得到结果q和余数r,再用除数b除以余数r 再得到一个余数,再用除数除以余数,…如此循环,直到余数为0,那么此时的除数就是最大公因数。

想要证明gcd(a,b) = gcd(b,a%b),需要简单了解下面两个引理:

  • 若d是a和b的公约数,那么d也是b和c的公约数(c为a%b)

  • 若d是b和c的公约数(c为a%b),那么d也是a和b的公约数

这两个引理的是什么意思呢,拿第一个来说;

假设一个数d是a的因子,也就是a=m*d,同时也是b的因子,b=n*d,那么a%b = a-w*b =  (m-w*n)*d;

由此可得,a的因子集合、b的因子集合和c的因子集合是相同的;

然后利用上述定理当余数为0的时候,除数就是最大公约数;



二、扩展欧几里得算法

    从字面上看,扩展欧几里得算法就是把欧几里得算法进行了扩展,不仅能求a和b的最大公约数,还其他功能,比如:

  • 求ax+by=m的任意一组解,最小整数解。

  • 求模逆元(模反元素)



为了了解学习上面的公式,需要先了解一个裴属定理



作者:亿万年的星光 分类:C++知识 浏览:

【数论】同余定理与同余方程

定义同余定理是数论中的一个重要概念。它的定义是这样的:给定一个整数m,如果两个整数a和b满足(a-b)能够被m整除,即(a-b)/m 得到一个整数,那么就成整数a和b对模m同余,记作a≡b(mod m)。对模m同余是整数的一个等价关系。简言之:两个整数同时除以一个整数得到的余数相同,则二整数同余。定理 两个整数a、b,若它们除以整数m所得的余数相等,则称a与b对于模m同余或a同余于b模m。  记作:a≡b (mod m),  读作:a同余于b
作者:亿万年的星光 分类:C++知识 浏览:

【算法】前缀和与差分(3)二维数组前缀和

0.前言前面的一篇文章,介绍了一维数组的前缀和,这篇文章中,介绍一下二维数组的前缀和1.定义二维数组的前缀和就是按照二维数组求和。公式如下:那二维前缀和中一个f[i][j]表示的意思就是以(1,1)为左上角以(i,j)为右下角这个矩阵里面数的和,可以用下面的这个图表示f[i][j]就是红色框的部分。举个例子:1 2 4 3 5 1 2 4 6 3 5 9如果按照公式进行计算,结果是:1 &nb

常见的数据范围

一、总结名称字节位数(二进制)最小值最大值位数(十进制)bool18011char18shrot 216    (-2^15  到2^15  -1)-32768327675int432    (-2^31 到 2^31  -1)-21474836482147483647 10unsigned int 4320429496729510long432-2147483648214748364710lon
作者:亿万年的星光 分类:C++知识 浏览:

C++中的逻辑与运算

  1. 样例



#include<iostream>  using namespace std;  int main(){  	cout<<(1&1)<<endl; //1   	cout<<(1&-1)<<endl; // 1   	cout<<(-1&-1)<<endl; //-1   	cout<<(-2&-3)<<endl; //-4   	return 0;  }



2.解释

 1&1:

      1    0000 0001  

      &   

      1    0000 0001  

-----------------------

      1    0000 0001   



 1&-1:

     

    

     1    0000 0001  

      &   

     -1   1111 1111  (补码)

-----------------------

      1    0000 0001   



解释:1的补码是1111 1111,然后进行逻辑与运算即可。



 -1&-1:

     

    

     -1   1111 1111  (补码)

      &   

     -1   1111 1111  (补码)

-----------------------

           1111 1111   



解释:负数和负数的逻辑与运算比较特殊。

-1 & -1 的直接结果是1111 1111,出符号位以外,剩下111 1111

然后把最低位减一得: 111 1110

然后按位取反得: 000 0001, 也就是1

加上符号就是-1,所以最后结果是-1



 -2&-3:



     -2   1111 1110 (补码)

      &   

     -3   1111 1101  (补码)

-----------------------

           1111 1100   



解释:

-2 & -3 的直接结果是1111 1100  ,出符号位以外,剩下111 1100

然后把最低位减一得: 111 1011

然后按位取反得: 000 0100, 也就是4

加上符号就是-1,所以最后结果是-4



作者:亿万年的星光 分类:C++知识 浏览:

字符串的输入输出汇总

做字符串的题目的时候,经常会遇到输入输出不对的情况,这篇文章就简单总结一下字符串常见的输入输出。2.cin基本操作:#include<iostream> #include<cstdio> #include<cstring> using namespace std; int main(){ char a[100]; cin>>a;   //hello cout<
作者:亿万年的星光 分类:C++知识 浏览:

【算法】分治算法

  1. 前言

    所谓分治算法就是指分而治之,即将较大规模的问题分解成几个较小规模的问题,通过对较小问题的求解达到对整个问题的求解。当我们将问题分解成两个较小问题求解时的分治方法称为二分法。

    比如,我们玩过最简单的猜数游戏,一开始,对方先想一个1000以内的正整数,然后你给出一个数x。对方只要回答“比x大”或者“比x小”或者“猜中”。

    开始猜测是1到1000之间,你可以先猜500。运气好的一次猜中,如果比500大,显然结果不是1到500之间,那么下一次就猜501到1000。如果比500下,那么下次就猜1到499。只要每次都猜测区间的中间点,这样就可以把猜测区间缩小一半。这样不超过10次询问区间就可以缩小为1,答案就会猜中了,这就是二分的基本思想。

  2. 基本思想及策略

    分治法的设计思想是:将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。

     分治策略是:对于一个规模为n的问题,若该问题可以容易地解决(比如说规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。这种算法设计策略叫做分治法。

      如果原问题可分割成k个子问题,1<k≤n,且这些子问题都可解并可利用这些子问题的解求出原问题的解,那么这种分治法就是可行的。由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便。在这种情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易直接求出其解。这自然导致递归过程的产生。分治与递归像一对孪生兄弟,经常同时应用在算法设计之中,并由此产生许多高效算法。

分治法适用的情况

分治法所能解决的问题一般具有以下几个特征:

1) 该问题的规模缩小到一定的程度就可以容易地解决

2) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。

3) 利用该问题分解出的子问题的解可以合并为该问题的解;

4) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。

第一条特征是绝大多数问题都可以满足的,因为问题的计算复杂性一般是随着问题规模的增加而增加;

第二条特征是应用分治法的前提它也是大多数问题可以满足的,此特征反映了递归思想的应用;、

第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑用贪心法或动态规划法。

第四条特征涉及到分治法的效率,如果各子问题是不独立的则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然可用分治法,但一般用动态规划法较好。

应用

(1)二分搜索

(2)大整数乘法
(3)Strassen矩阵乘法
(4)棋盘覆盖
(5)合并排序
(6)快速排序
(7)线性时间选择
(8)最接近点对问题
(9)循环赛日程表
(10)汉诺塔

 (11)一元三次方程求解



快速排序:

void qsort(int left, int right){  	int i=left; j =right;  	mid=a[left+right]/2;  	while(i<=j){  		while(a[i]<mid) i++;   		while(a[j>mid]) j--;  		if(i<=j){  			swap(a[i],a[j]);  			i++;  			j--;  		}  	}  	if(left<j) qsort(left,j);  	if(i<right) qsort(i,right);  }

一元三次方程求解:

描述

有形如:ax3+bx2+cx+d=0 这样的一个一元三次方程。



给出该方程中各项的系数(a,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差的绝对值>=1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位。



输入

一行,包含四个实数a,b,c,d,相邻两个数之间用单个空格隔开。

输出

一行,包含三个实数,为该方程的三个实根,按从小到大顺序排列,相邻两个数之间用单个空格隔开,精确到小数点后2位。

样例输入

1.0 -5.0 -4.0 20.0

样例输出

-2.00 2.00 5.00

作者:亿万年的星光 分类:C++知识 浏览: