标签:
第二章:数学基础
基本计数方法:
在这一章节中有关基本的计数原理、容斥原理、二项式系数恒等式这里不再体现,这个专栏主要通过具体的题目来提升对理论知识的应用。
下面我们来看两个基本计数问题:
ex1:可重复选择的组合:有n个不同元素,每个元素可以选多次,一共选k个元素有多少方法?
分析:设第i种元素选取的数量是xi,则我们可以将问题转化成x1+x2+…xn = k的非负整数解(x1,x2,….,xn)的组数。其实此时我们就容易想到插入隔板的方法,我们赋予这个等式一个组合含义,即像k个1形成的k-1个间隔中插入n-1个隔板,这个动作的情况数即是n元解的组数,但是我们列出计数公式发现是C(k-1,n-1),虽然在《具体数学》一书中给出了这种组合数的含义,但是在这里对于我们来说并不好理解。
我们采用迂回一点的策略,建立一一映射关系:yi = xi+1,则原方程等价转化成y1 + y2…yn = k + n的n元非负整数解的个数,这样一来,我们依然采用上面插入隔板的原理,可以得到计数公式C(n+k-1,n-1) = C(n+k-1,k)。
ex2:单色三角形:给定空间里的n(n≤1000)个点,其中没有三点共线。每两个点之间都用红色或者黑色线段连接(可以通过矩阵的形式给出关系图)。求3条边同色的三角形个数。
分析:暴力法显然理论可解,但是时间复杂度是O(n^3),我们需要优化。从反面考虑,去寻求非单色三角形,我们容易看到,非单色三角形必有两个点,这两个点连接的两个不同颜色的边,那么我们从点连接边的情况来考虑,对于第i个点vi,我们假设有ai个红边,显然vi连接着n-1-ai个黑边,那么由此我们就能构造出ai(n-1-ai)个非单色三角形,结合我们刚才观察的结果,会发现这种计算模式会把每个非单色三角形计算两次,即最终非单色三角形的个数是1/2∑ai(n-1-ai)。
下面让我们看一些竞赛中的组合计数题目。
Uva11538:
给出n x m的棋盘,放入两个皇后,能够形成多少种局面,使得这两个皇后能够互相攻击。
分析:既然这道题没有告诉你正方形的棋盘能够旋转之类的限制,那么我们就不去考虑用polya原理去重。
首先基于国际象棋中皇后的走法,它走水平线、竖直线、斜线,因此这里为了使两个皇后能够互相攻击,我们就从这三种情况进行分析,我们分别记这三种情况为A(n,m)、B(n,m)、C(n,m)。假设n是行,m是列。
(1) 水平线:先放入一个皇后,有nm种方法,则另一个皇后有m-1种方法。即A(n,m) = mn(m-1)
(2) 竖直线:先放入一个皇后,有nm种方法,则另一个皇后有n-1种方法。即B(n,m) = nm(n-1)
(3) 斜线:我们先假设一个大小关系——m>n,因为这将限制我们得到的斜线的组数,那么基于这个假设,我们将得到如下的对角线长度序列:
1,2,3,4…n-2,n-1,n,n,n…n,n,n(m-n+1个n)…n-1,n-2,4,3,2,1,另外还要考虑到这样的对角线有两组。
那么我们易知,C(n,m) = 2[2∑i(i-1) + (m-n+1)n(n-1)]。
而对于一开始我们对于m>n的假设,我们这样处理,将传进来的两个参数较大的赋给m,这样就用一个公式便可以完成计算了。
然后进行化简,即可编程实现。
简单的参考代码如下。
#include<cstdio> #include<algorithm> using namespace std; int main() { long long n ,m; while(scanf("%lld%lld",&n,&m)!= EOF) { if(n == 0 && m == 0) break; if(m < n)//保证n≤m swap(n,m); printf("%lld\n",m*n*(m+n-2) + 2*n*(n-1)*(3*m-n-1)/3); } }
标签:
原文地址:http://www.cnblogs.com/rhythmic/p/5571924.html