HDU 5729 Rigid Frameworks(组合计数,递推)
2016-07-21 09:25
429 查看
[题目链接]
[题意]
赛上就没读懂过题意…
通过转换将问题变为求两个点集大小分别为n和m的连通二分图个数,其中每条边可以有2种选择(主副对角线)
[分析]
如果每条边只有1种选择,那就变成了Project Euler 434,所以我们先来考虑这个问题
对于n,m点的二分图,若不考虑连通性的限制,那么总方案数为2n∗m
只要再减去不连通的情况即可
如何不重复不遗漏的计算出不连通的方案数呢?
这里本弱学习了一种看起来十分靠谱的递推方案
设有n,m点的两个点集(A,B),使其连通的连边方案数为f(n,m)
从A中选i个点,B中选j个点 的方案数为Cin∗Cjm,使其连通的方案数为f(i,j)
对于每一种选法,设两个点集剩余部分为(A′,B′),只要保证A′与B间以及A与B′间没有任何边,整个二分图就不连通,所以A′与B′间可以任意连边,方案数为2(n−i)(m−j)
枚举i和j,依次减去即可
但注意到,这样枚举是会有重复计算的
比如,在选取前i个点与前j个点时,对应于取后n-i点和后m-j点,会有重复统计的情况
为了避免这种情况,我们可以在A中固定取第一个点,在剩余的n-1个点中取i-1个点,而B的取法不变,这样做就能做到不重复不遗漏
因为所有不包含A中第一个点的方案都被对称的统计了,而且这样选取是不会出现重复的
f(n,m)=2n∗m−∑0<i<=n0<=j<=mi+j<n+mf(i,j)∗Ci−1n−1∗Cjm∗2(n−i)∗(m−j)
在加入边的选择后, 只需要多存一维边数,枚举的时候也多枚举一维边数即可
任意连k条边的方案数为Ckn∗m
f(n,m,k)表示边数为k,两个点集大小为n和m的连通二分图数量
f(n,m,k)=Ckn∗m−∑0<i<=n0<=j<=m0<=s<=ki+j<n+mf(i,j,s)∗Ci−1n−1∗Cjm∗Ck−s(n−i)∗(m−j)
最终答案为
ans=∑i=0n∗mf(n,m,i)∗2i%mod
[代码]
[更新]
发现自己简直是zz
根本不需要再加一维边数
每个格子的选择就3种,不连,连主对角线,连副对角线
所以只需要把PE 434 中的2n改为3n
f(n,m)=3n∗m−∑0<i<=n0<=j<=mi+j<n+mf(i,j)∗Ci−1n−1∗Cjm∗3(n−i)∗(m−j)
这样之后0ms通过,代码量也少了很多
[代码]
[题意]
赛上就没读懂过题意…
通过转换将问题变为求两个点集大小分别为n和m的连通二分图个数,其中每条边可以有2种选择(主副对角线)
[分析]
如果每条边只有1种选择,那就变成了Project Euler 434,所以我们先来考虑这个问题
对于n,m点的二分图,若不考虑连通性的限制,那么总方案数为2n∗m
只要再减去不连通的情况即可
如何不重复不遗漏的计算出不连通的方案数呢?
这里本弱学习了一种看起来十分靠谱的递推方案
设有n,m点的两个点集(A,B),使其连通的连边方案数为f(n,m)
从A中选i个点,B中选j个点 的方案数为Cin∗Cjm,使其连通的方案数为f(i,j)
对于每一种选法,设两个点集剩余部分为(A′,B′),只要保证A′与B间以及A与B′间没有任何边,整个二分图就不连通,所以A′与B′间可以任意连边,方案数为2(n−i)(m−j)
枚举i和j,依次减去即可
但注意到,这样枚举是会有重复计算的
比如,在选取前i个点与前j个点时,对应于取后n-i点和后m-j点,会有重复统计的情况
为了避免这种情况,我们可以在A中固定取第一个点,在剩余的n-1个点中取i-1个点,而B的取法不变,这样做就能做到不重复不遗漏
因为所有不包含A中第一个点的方案都被对称的统计了,而且这样选取是不会出现重复的
f(n,m)=2n∗m−∑0<i<=n0<=j<=mi+j<n+mf(i,j)∗Ci−1n−1∗Cjm∗2(n−i)∗(m−j)
在加入边的选择后, 只需要多存一维边数,枚举的时候也多枚举一维边数即可
任意连k条边的方案数为Ckn∗m
f(n,m,k)表示边数为k,两个点集大小为n和m的连通二分图数量
f(n,m,k)=Ckn∗m−∑0<i<=n0<=j<=m0<=s<=ki+j<n+mf(i,j,s)∗Ci−1n−1∗Cjm∗Ck−s(n−i)∗(m−j)
最终答案为
ans=∑i=0n∗mf(n,m,i)∗2i%mod
[代码]
#include <bits/stdc++.h> using namespace std ; const int N = 11 ; const int M = 101 ; const int mod = 1e9 + 7 ; typedef long long LL ; int n , m ; LL f [M] , p2[M] ; LL C[M][M] ; int ans ; void init() { C[0][0] = p2[0] = 1 ; for( int i = 1 ; i < M ; i++ ) { p2[i] = p2[i-1]*2%mod ; C[i][i] = C[i][0] = 1 ; for( int j = 1 ; j < i ; j++ ) C[i][j] = ( C[i-1][j-1] + C[i-1][j] ) % mod ; } memset(f,-1,sizeof(f)) ; } LL dfs( int n , int m , int k ) { if( n < m ) swap(n,m) ; if( ~f [m][k] ) return f [m][k] ; LL sum = 0 ; for( int i = 1 ; i <= n ; i++ ) { for( int j = 0 ; j <= m ; j++ ) { if( i == n && j == m ) continue ; for( int s = 0 ; s <= k ; s++ ) { sum += dfs(i,j,s)*C[n-1][i-1]%mod*C[m][j]%mod*C[(n-i)*(m-j)][k-s]%mod ; } } } return f [m][k] = ( C[n*m][k] - sum%mod + mod ) % mod ; } int main() { init() ; while( ~scanf( "%d%d" , &n , &m ) ) { LL ans = 0 ; for( int i = 0 ; i <= n*m ; i++ ) { ans += dfs(n,m,i)*p2[i]%mod ; } printf( "%I64d\n" , ans%mod ) ; } return 0 ; }
[更新]
发现自己简直是zz
根本不需要再加一维边数
每个格子的选择就3种,不连,连主对角线,连副对角线
所以只需要把PE 434 中的2n改为3n
f(n,m)=3n∗m−∑0<i<=n0<=j<=mi+j<n+mf(i,j)∗Ci−1n−1∗Cjm∗3(n−i)∗(m−j)
这样之后0ms通过,代码量也少了很多
[代码]
#include <bits/stdc++.h> using namespace std ; const int N = 11 ; const int M = 101 ; const int mod = 1e9 + 7 ; typedef long long LL ; int n , m ; LL f , p3[M] ; LL C[M][M] ; int ans ; void init() { C[0][0] = p3[0] = 1 ; for( int i = 1 ; i < M ; i++ ) { p3[i] = p3[i-1]*3%mod ; C[i][i] = C[i][0] = 1 ; for( int j = 1 ; j < i ; j++ ) C[i][j] = ( C[i-1][j-1] + C[i-1][j] ) % mod ; } memset(f,-1,sizeof(f)) ; } LL dfs( int n , int m ) { if( n < m ) swap(n,m) ; if( ~f [m] ) return f [m] ; LL sum = 0 ; for( int i = 1 ; i <= n ; i++ ) { for( int j = 0 ; j <= m ; j++ ) { if( i == n && j == m ) continue ; sum += dfs(i,j)*C[n-1][i-1]%mod*C[m][j]%mod*p3[(n-i)*(m-j)]%mod ; } } return f [m] = ( p3[n*m] - sum%mod + mod ) % mod ; } int main() { init() ; while( ~scanf( "%d%d" , &n , &m ) ) { printf( "%I64d\n" , dfs(n,m) ) ; } return 0 ; }
相关文章推荐
- SpringMVC学习笔记
- java中转发和重定向的区别
- jQuery的ajax下载blob文件
- Swift3中如何为Array写一个限定Type的扩展
- Swift3中如何为Array写一个限定Type的扩展
- Swift3中如何为Array写一个限定Type的扩展
- Spring 4 + Reactor Integration Example--转
- 添加看门狗程序
- The Python Tutorial - Data Structures
- 详解Android中AsyncTask的使用
- groovy语法基础
- java连接JDBC
- 指针的定义和使用
- 直接拿来用,最火的Android开源项目
- 转:使用Nlog记录日志到数据库
- Mac: the original hosts
- OC_模糊搜索
- leetcode_376. Wiggle Subsequence(DP 和 Greedy)
- Hadoop:hadoop的起缘和发展史
- Linux学习笔记--设备(主要指存储设备)挂载目录