POJ 2411 状压DP||组合数学
2017-07-31 15:40
183 查看
题意
1*2的牌放入N*M的网格中,问有多少种摆放方案。题解
两种解决方案。第一种,组合数学有一个专门的公式解决这个问题。
感谢周伟大佬提供的公式,ORZ。。(同时强烈推荐读者阅读周伟的状压DP论文)
第二种,状态压缩
相比于组合数学公式,状态压缩的效率就低很多,但是由于公式不太可能短时间内推导出来,所以在比赛和做题的时候,还是状态压缩方法比较通用和便捷一些。
关于这种放牌的问题,周伟大佬称之为覆盖模型,并表明覆盖模型其实就是棋盘模型的变体。我表示完全同意。解决这个问题,依然是老办法,针对每一行,枚举每一行的状态,然后判断这一行与上一行的状态是否发生冲突,若不发生冲突则代表这一行的状态可以由上一行的状态转移而来。反复操作,直到转移到第H-1行,即可得到问题的解。
套路是死的,但是问题还是有一定的灵活性。关于这道题,最大的问题就在于冲突的判断。首先,对于第一行,需要特殊判断。第一行只能有两种摆放方式,横着放和竖着放第一个。第一行绝不可能是竖着放的第二个元素。因此,针对第一行的枚举只需要过滤这一种情况即可。假设竖着放第一个是0,其他是1。则1必须连续出现。过滤掉不连续出现1的情况即可。
对于其他行,则需要与上一行是否冲突进行判断。如果这一行是0,则上一行的这个位置只能是1。如果这一行是1,则上一行的这个位置可能是0,也可能是1。如果上一行的这个位置是1,则代表这一行是横着放的。因此下一个元素也是1,由于是横着放的,所以下一个元素的上一行不能竖着放,因此下一个元素的上一行也是1。
根据上述两个判断条件,就可以很好的完成状态转移。
注意事项
写程序的时候有点晕,犯了不少错误。首先的话,注意一下位运算的优先级吧,位运算优先级很低,所以一定要注意加括号。第二点的话,就是注意一下(x&(1 << pos))这种运算的运算结果,这种运算可以判断某一位的值是否为0。也就是是否选择了某一位。但是一定要注意,如果不为0,并不代表这一位为1。。。
代码
#include<bits/stdc++.h> #define UP(i,l,h) for(int i=l;i<h;i++) #define DOWN(i,h,l) for(int i=h-1;i>=l;i--) #define W(a) while(a) #define INF 0x3f3f3f3f #define LL long long #define MAXN 2100 #define EPS 1e-10 #define MOD 100000000 using namespace std; int w,h; LL dp[15][MAXN]; bool check(int s) { int pos=0; W(pos<w) { if((s&(1<<pos))==0) { pos++; } else { if((s&(1<<(pos+1)))==0||pos==(w-1)) { return false; } pos+=2; } } return true; } bool checkAB(int a,int b) { int pos=0; W(pos<w) { if((a&(1<<pos))==0) { if((b&(1<<pos))==0) { return false; } else { pos++; } } else { if((b&(1<<pos))==0) { pos++; } else if(pos==(w-1)||(b&(1<<(pos+1)))==0||(a&(1<<(pos+1)))==0) { return false; } else { pos+=2; } } } return true; } int main() { W(~scanf("%d%d",&h,&w)) { if(w+h==0) break; if(h>w) swap(h,w); memset(dp,0,sizeof(dp)); UP(i,0,1<<w) { if(check(i)) { dp[0][i]=1; } } UP(k,1,h) { UP(i,0,1<<w) { UP(j,0,1<<w) { if(checkAB(i,j)) { dp[k][i]+=dp[k-1][j]; } } } } printf("%lld\n",dp[h-1][(1<<w)-1]); } }
相关文章推荐
- poj 1019 Number Sequence 第i位上的数字 (组合数学)
- POj 2249 Binomial Showdown 【组合数学】
- POJ 2282 The Counting Problem,组合数学
- POJ 3734 Blocks 组合数学
- POJ——2249(组合数学)
- poj 1019 Number Sequence (组合数学)
- POJ 1942 Paths on a Grid 找规律+组合数学
- POJ 3252 Round Numbers 组合数学
- POJ 2154 Color(组合数学-波利亚计数,数论-欧拉函数,整数快速幂)
- poj2992数论与组合数学,略水。。。
- poj 2411 Mondriaan's Dream 【状压dp】
- POJ 3731 (组合数学)
- POJ-1850-Code-组合数学
- T解 POJ-2411 Mondriaan's Dream [轮廓线DP] || [状压DP]
- POJ 3252 组合数学?
- POJ - 1850 Code(组合数学推公式)
- POJ 1715 Hexadecimal Numbers 组合数学
- (组合数学3.1.2.2)POJ 1306 Combinations(c[i][j] = c[i-1][j] + c[i-1][j-1]的实现)
- POJ 1942 Paths on a Grid【组合数学】
- POJ 3252 Round Numbers (组合数学/数位dp)