hdu5155(Harry And Magic Box) DP+组合容斥原理 BC25
来源:互联网 发布:微信刷步软件 编辑:程序博客网 时间:2024/05/17 20:01
在这里提供三个版本(2DP+1组合&容斥原理)--在学校的我就是耐得住寂寞-- 对于知识就是得fussy~~
链接:http://acm.hdu.edu.cn/showproblem.php?pid=5155
题意:nxm的棋盘,要求每行每列至少放一个棋子的方法数。dp[i][j]表示前 i 行有 j 列都有了棋子,且每行也有棋子。fussy
官方:dp题,我们一行一行的考虑。dp[i][j],表示前i行,都满足了每一行至少有一个宝石的条件,而只有j列满足了有宝石的条件的情况有多少种。枚举第i+1行放的宝石数k,这k个当中有t个是放在没有宝石的列上的,那么我们可以得到转移方程:dp[i+1][j+t]+=dp[i][j]*c[m-j][t]*c[j][k-t],其中c[x][y],意为在x个不同元素中无序地选出y个元素的所有组合的个数。
#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <algorithm>#define Mod 1000000007#define lll __int64using namespace std;lll c[55][55];lll dp[55][55];void calc(){ for(int i=0;i<=51;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; //组合公式c[i][j] = (c[i-1][j-1]+c[i-1][j]); }}int main(){ int n,m,i,j,k,t; calc(); while(scanf("%d%d",&n,&m)!=EOF) { memset(dp,0,sizeof(dp)); for(i=1;i<=m;i++)dp[1][i]=c[m][i]; for(i=1;i<=n;i++) //第i行 { for(k=1;k<=m;k++) //1.枚举共本行放多少个 { for(t=0;t<=k;t++) //2.枚举新增个数 { for(j=max(1,k-t);j+t<=m;j++) { dp[i][j+t] = (dp[i][j+t]+dp[i-1][j]*c[m-j][t]%Mod*c[j][k-t]%Mod)%Mod;/*本次种数+=上次种数 * 产生新列组合种数(c[m-j][t]:在未覆盖的m-j列中选t列) * 不产生..(在已覆盖的j列中选k-t列)c[m-j][t]枚举第i+1行放的宝石数k,这k个当中有t个是放在没有宝石的列(m-j)上的c[j][k-t]表示剩下的k-t个在原来那j个有棋子的列去放,这样放不会增加至少有一个棋子的列。1.枚举第i行放的宝石数k;2.这k个当中有t个是放在没有宝石的列上的1和2是因为新增的个数t是这行内的k(1<=k<=n)中所包含,如新增t=1,可以是本行放2或3个时候的.(即枚举所有可能情况)*/ } } } } printf("%I64d\n",dp[n][m]%Mod); } return 0;}
这题做法: 从第1行到第n行,枚举这一行有k列已至少有一个,再枚举前一行有j列至少有一个,然后
枚举这一行新放多少个棋子t,至少一个(因为每行至少一个)
C[m-j][k-j]表示新增的那些原来没棋子现在有棋子的列k-j列分别可以放到上一行没放的地方m-j个地方,
这样放会增加至少有一个棋子的列
C[j][t-(k-j)]表示剩下的在原来那j个有棋子的列去放,这样放不会增加至少有一个棋子的列。
个人认为上面那个DP比较好理解。。
<pre name="code" class="cpp">#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <algorithm>#define Mod 1000000007#define lll __int64using namespace std;lll c[55][55];lll dp[55][55];void calc(){ for(int i=0;i<=51;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; //组合公式c[i][j] = (c[i-1][j-1]+c[i-1][j]); }}int main(){ int n,m,i,j,k,t; calc(); while(scanf("%d%d",&n,&m)!=EOF) { memset(dp,0,sizeof(dp)); dp[0][0] = 1; for(i=1;i<=n;i++) { for(k=1;k<=m;k++) //这一行得多少个亮(稍微模拟即明) { for(j=0;j<=k;j++) //上一行已有多少个亮(1至i-1行有多少列亮) { for(t=max(1,k-j);t<=k;t++) //枚举共本行放多少个 { dp[i][k] = (dp[i][k]+dp[i-1][j]*c[m-j][k-j]%Mod*c[j][t-(k-j)]%Mod)%Mod;//本次种数+=上次种数 * 产生新列组合种数(c[m-j][k-j]:在未覆盖的m-j列中选k-j列) * 不产生..(在已覆盖的j列中选t-(k-j)列)//dp[i][k]:dp[i][j+(k-j)]+=dp[i-1][j]*c[][k-j]*c[][]; } } } } printf("%I64d\n",dp[n][m]%Mod); } return 0;}
组合+容斥原理
/*在n*m的矩阵中,枚举每一行有i列不存在钻石(注意枚举出的是i个1*n的小矩形且可以可拼成n*i的矩形,且这些必定是都不放)(因为n=3时,选出的两列或许是1和3(被中间的2隔开了)那么共有C(m,i)种排列。(从m列中选出的是i个1*n的小矩形)每行对于其他的m-i列中可以放也可以不放,但是要排除全都不放的情况,得到每行有2^(m-i)-1种(-1:每行排除全不放),再加上n行得到(2^(m-i)-1)^n)得到f(i) = C(m,i) * (2^(m-i)-1)^n ;容斥原理排除多余的 f(0) - f(1) + f(2)-f(3)+...f(n-1) ;n=2,m=3时,f(0)=49:0列不放,即全列,则包含放两行的,故-f(1)f(1)=27:1列不放,则包含放1行的两次(多-了次)(画图看看就明),故+f(2)f(2)=3 :2列不放,即等于m如此类推,发现当前-f(i)下次+回f(i+1)//*/#include<cstring>#include<string>#include<iostream>#include<cmath>#include<bitset>using namespace std;#define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i )typedef __int64 LL;typedef pair<int,int>pil;const int maxn=55;const int MOD=1000000007;LL c[maxn][maxn];//2^(m-i)-1;int n,m;void init(){ REPF(i,1,50) { c[i][0]=c[i][i]=1; REPF(j,1,i-1) c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD; }}LL pow_mod(LL a,int b){ a%=MOD; LL ans=1; while(b) { if(b&1) ans=ans*a%MOD; a=a*a%MOD; b>>=1; } return ans;}int main(){ init(); while(~scanf("%d%d",&n,&m)) { LL ans=0;REPF(i,0,m-1) {LL tn=1,c1=m-i;//(1LL<<(m-i));while(c1--)tn<<=1; if(i&1) ans=(ans-(pow_mod(tn-1,n)*c[m][i])%MOD+MOD)%MOD; else ans=(ans+(pow_mod(tn-1,n)*c[m][i])%MOD)%MOD;//printf("i=%d ans=%I64d pow=%I64d tn=%I64d\n",i,ans,//(pow_mod(tn-1,n)),tn); } printf("%I64d\n",ans); } return 0;}
0 0
- hdu5155(Harry And Magic Box) DP+组合容斥原理 BC25
- hdu5155---Harry And Magic Box
- HDU5155 Harry And Magic Box
- HDU 5155 Harry And Magic Box(组合+容斥)
- hdu--5155Harry And Magic Box(组合数+容斥原理)
- 【HDU】5155 Harry And Magic Box 【容斥原理】
- HDU 5155 Harry And Magic Box(容斥+组合数学)
- HDU 5147 Harry And Magic Box dp+组合数
- HDU-5155 Harry And Magic Box(DP,组合数)
- hdu 5155 Harry And Magic Box(DP)
- Harry And Magic Box (dp题)
- HDU 5155 Harry And Magic Box --DP
- HDOJ 5155 Harry And Magic Box DP
- Harry And Magic Box
- HDU 5155 Harry And Magic Box DP题
- hdu 5155 Harry And Magic Box
- HDU - 5155 Harry And Magic Box
- HDU 5155 Harry And Magic Box
- iOS 访问Default.png图片
- 爪字坠遵诅卒桩淄仔桩琢做桩紫族淄滓紫
- IOS多线程开发-NSThread原理及演示
- Linux学习笔记之目录
- 注着篆揍卓桌嘴状锥总抓桌卒鬃抓转滋宗
- hdu5155(Harry And Magic Box) DP+组合容斥原理 BC25
- 醉祝鬃谞篆总浊鬃茁驻卓祝罪孜捉庄仔邹
- 怎样编写格式优美的代码
- Q侠传问题技术总结
- 好书推荐-腾讯方法:一个市值1500亿美元公司的产品真经
- Linux软链接和硬链接
- Linux学习笔记之基本命令二(目录和文件)
- Java 实现把异常信息写入到文件中
- RelativeLayout介绍