组合数学-排列组合整理
来源:互联网 发布:基于用户协同过滤算法 编辑:程序博客网 时间:2024/06/08 04:43
此文是我整理组合数学排列组合知识的博文,排列组合从零开始。。。加油!
1.重复组合:
HDU 5894 hannnnah_j’s Biological Test (组合数学)
题目大意:有n张板凳围成一圈,有m个人,要让m个人都坐到凳子上且任意两人之间相隔>=k 个凳子,问有多少种方法%(1e9+7)
题目思路:组合数学
我们这样考虑,既然每个人相距>=k 个凳子,m个人就至少有m*k个凳子不能坐人,那我们先从中抽出这m*k个凳子,其它
凳子都可以坐了,然后我们考虑第一个人坐到了一个位置上,剩下的人就有C(n-m*k-1,m-1)种坐法,而第一个人有n种
初始选择,但由于m个人又相同,故应该是C(n-m*k-1,m-1)*n/m种坐法。
总结:我们可以这样想, 先把m个人安排好, 每个人之间有k个座位,那样剩下的随意插到两个人之间就好了, 所以是 剩下n-m*k-m凳子, 插到m个空里,可以有空,问有几种分法,相当于将m个相同小球放到n个不同的位置,故共有组合数为C上标n-1下标n+m-1;对于环来说, 确定了一个起点,这个环就唯一确定了, 可以唯一被拉成一条链,而每个凳子,我都可以做这个环的起点,又因为m个人是一样的, 所以m个人当作起点的时候,情况重复了m次,这里在一个环里放1一个,放在哪都是一样,无所谓的, 所以直接可以C(n-m*k-1,m-1),下一题就不一样了
#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;typedef long long ll;const int maxn = 1e6 + 7;const int Mod = 1e9 + 7;ll inv[maxn], cnt[maxn], f2[maxn];void init(){ cnt[0] = cnt[1] = 1; inv[0] = inv[1] = 1; f2[0] = f2[1] = 1; for(int i = 2; i < maxn; i++) { cnt[i] = (cnt[i-1]*i)%Mod; //阶乘 inv[i] = (Mod-Mod/i)*inv[Mod%i]%Mod; //线性求逆元 f2[i] = f2[i - 1] * inv[i] % Mod; }}ll C(ll x, ll y) //C(x, y){ if(x < y || y < 0) return 0;// return (cnt[x]*inv[y])%Mod*inv[x-y]%Mod; return cnt[x] * f2[y] % Mod * f2[x - y] % Mod; //线性求组合数}int main(){ int T; ll n, m, k; init(); cin >> T; while(T--) { scanf("%lld%lld%lld", &n, &m, &k); if(m == 1) { printf("%lld\n", n); continue; } printf("%lld\n", n*C(n-m*k-1, m-1)%Mod*inv[m]%Mod); } return 0;}
hihoCoder 1075 开锁魔法III DP+组合数
描述
一日,崔克茜来到小马镇表演魔法。
其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它。初始时,崔克茜将会随机地选择 k 个盒子用魔法将它们打开。崔克茜想知道最后所有盒子都被打开的概率,你能帮助她回答这个问题吗?
输入
第一行一个整数 T (T ≤ 100)表示数据组数。 对于每组数据,第一行有两个整数 n 和 k (1 ≤ n ≤ 300, 0 ≤ k ≤ n)。 第二行有 n 个整数 ai,表示第 i 个盒子中,装有可以打开第 ai 个盒子的钥匙。
输出
对于每组询问,输出一行表示对应的答案。要求相对误差不超过四位小数。
45 12 5 4 3 15 22 5 4 3 15 32 5 4 3 15 42 5 4 3 1
0.0000000000.6000000000.9000000001.000000000
思路:首先可以很明显的知道,总方案数是C(n,k), 这个可以变成cnt个环, 如果开k次, 每个环里各有一次,那就可以。这题跟上题有点像? 是不是可以每个环我都开一次, 那么其余就是重复组合问题了, C(m-1, m+cnt-1)就好了?但是这样是错误的。。首先每个盒子是不一样的, 你开不同盒子方案是不一样,那是不是每个环第一次开有num[i](每个环的元素个数)中选择?那我把第一次所有可能都乘起来就好? 答案是不对的, 那你剩下的k-cnt的钥匙,重复组合的放到n-cnt里,对于每个放到环里的钥匙,他不是开任意一个都是一样的。。因为每个箱子不同, 上面那题放凳子, 你在一个空里放k个,他放在哪都是无所谓的。。。这题应该,比如我第i个环我要放x个, 那么他的方案数是 C(num[i], x),从num【i】里选x个开开,而不是重复组合,随意分给每个环几个, 一旦确定分几个,他环里面还是要组合数的,所以这题不能重复组合,或者这样理解, 重复组合是n个无区别的小球,放到m个有区别的盒子,这里的k次魔法应该理解成不相同的,每个环里的盒子不同,他开哪个都不同,正解是dp+组合数,也很好理解
还有一种想法:C(n-m,k-m)*(πnum[i]//代表num从1乘到n)/C(n,k),m为环的个数,我一定要将每个环都选一个点才行,那么就剩下了n-m个点,在其中选k-m个点的方案数就是所有可行解的方案数,这样会有很多重复的。。dp的好处就是去掉了重复的情况。。。dp[i][j] += dp[i-1][j-cur]*C[num[i]][cur]; dp[i][j]代表前i个用j个魔法,cur枚举第i个用的魔法数量,方程很显而易见,不会有重复。
正解:由于我们可以通过魔法打开一个箱子,随后用其中的钥匙打开下一个箱子,然后再次进行相同动作,直到再次得到最初用魔法打开的箱子的钥匙。我们把这几个箱子看作一组、称作一个“循环”。那么n个箱子会被我们分作sum个组,每组里有多少个箱子我们存储在part里,为了供下一步的dp推算使用。
我们用一个二维dp数组,dp[i][j]表示用了j次魔法,能够解决i个分组的概率。其中dp[0][0] = 1.0,对于每个分组,我们可能使用几次魔法,也需要进行一次组合数来计算。最终,我们将dp[sum][n]除以总可能数C(n, k),即得到最终答案。
#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;const int maxn = 3e2 + 7;double C[maxn][maxn], dp[maxn][maxn];int a[maxn], num[maxn], book[maxn];void init(){ for(int i = 0; i < maxn; i++) { C[i][0] = C[i][i] = 1; for(int j = 1; j < i; j++) { C[i][j] = C[i-1][j-1] + C[i-1][j]; } }}int main(){ int T, n, k; cin >> T; init(); while(T--) { memset(book, 0, sizeof(book)); memset(dp, 0, sizeof(dp)); int tot = 0; scanf("%d%d", &n, &k); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); for(int i = 1; i <= n; i++) { if(book[i]) continue; int index = a[i], cnt = 1; while(index != i) { book[index] = 1; index = a[index]; cnt++; } if(cnt) num[++tot] = cnt; } dp[0][0] = 1; for(int i = 1; i <= tot; i++) { for(int cur = 1; cur <= num[i]; cur++) { for(int j = cur; j <= k; j++) dp[i][j] += dp[i-1][j-cur]*C[num[i]][cur]; } } printf("%.9f\n", dp[tot][k]/C[n][k]); } return 0;}
- 组合数学-排列组合整理
- 组合数学->排列组合
- 算法_3 : 组合数学:排列组合
- 组合数学之排列组合若干题
- 关于数学中排列组合之组合算法实现
- HDU 4043 FXTZ II (组合数学-排列组合)
- 组合数学-利用挡板法解排列组合题
- HDU 4372 Count the Buildings(组合数学-斯特林数,组合数学-排列组合)
- HDU 4045 Machine scheduling (组合数学-斯特林数,组合数学-排列组合)
- 组合数学之排列组合(Permutations and Combinations)(四种情况)
- (组合数学3.1.2.1)POJ 2249 Binomial Showdown(排列组合公式的实现)
- UVa 10290 {Sum+=i++} to Reach N (数论-整数和素数,组合数学-排列组合)
- 组合数学之排列组合(Permutations and Combinations)(四种情况)
- 排列组合------组合篇
- hdu 1521 排列组合 组合
- 数学中的排列组合
- 组合数学
- 组合数学
- 相机标定的理解及采用opencv和matlab工具箱的标定方法
- Touch事件--对Scroller的理解
- 使用weixin java tools学习(笔记)
- 安卓如何做到当在未来的某一天触发一些事件,获取网络时间
- 多态、malloc和new的区别
- 组合数学-排列组合整理
- Ashmem、MemoryFile、Binder的共享内存(jni可用)
- stm32 IIC通信
- 学习网站
- 技术-Java程序调用外部程序获取输出
- LeetCode (28)Implement strStr()
- 第九周OJ-Q16解题方法
- cocos2dx-lua基础内容之 坐标系的转换
- 第四章 栈