HDU 4084 Campus Design 状压dp
来源:互联网 发布:db2数据库的一些操作 编辑:程序博客网 时间:2024/05/29 19:48
题意:在n*m的格子里面放1*1和1*2的砖块,要求不能放在格子为0的地方,并且使用1*1的数目在[c,d]之间,求方案总数。
想了一天也没有想到有效的转移,其实是陷入了一种错误的想法中,转移应该是一块一块的,不应该是一层一层的,终于在看过了别人的代码以后明白了。
又跟学长交流了一下,经过学长的指导,发现是自己想轴了,一层一层的转移也是可行的,比较一下两个方式的复杂度,一块一块的转移是O(n*m*d*2^m)1437 ms,一层一层的转移是O(n*d*2^m*dfs一层的复杂度)6406 ms,试了一下,也是可以AC的。
一块一块的转移
#include <iostream> #include <stdio.h> #include <string.h> using namespace std; const int mod=1000000007; char s[110][12]; int n,m,c,d; int dp[2][1100][25]; int now,next; void update(int nextp,int p,int nextk,int k) { dp[next][nextp][nextk]+=dp[now][p][k]; if (dp[next][nextp][nextk]>=mod) dp[next][nextp][nextk]-=mod; } int main() { // freopen("in.txt","r",stdin); while (~scanf("%d%d%d%d",&n,&m,&c,&d)) { for (int i=1;i<=n;i++) scanf("%s",s[i]); memset(dp,0,sizeof(dp)); dp[0][(1<<m)-1][0]=1; now=0; for (int i=1;i<=n;i++) for (int j=0;j<m;j++) { next=now^1; //状态表示的是当前格子的前m块格子是否放砖的情况; if (s[i][j]=='0') { for (int k=0;k<=d;k++) for (int p=(1<<(m-1));p<(1<<m);p++)//格子是'0',什么也不放,并且必须保证这个格子的上面那个格子放过了; if (dp[now][p][k]) update(((p<<1)-(1<<m))^1,p,k,k); } else//格子是'1'; { for (int k=0;k<=d;k++) for (int p=(1<<(m-1));p<(1<<m);p++)//什么也不放,并且必须保证这个格子的上面那个格子放过了; if (dp[now][p][k]) update(((p<<1)-(1<<m)),p,k,k); for (int k=0;k<=d;k++) for (int p=(1<<(m-1));p<(1<<m);p++)//放1*1,并且必须保证这个格子的上面那个格子放过了; if (dp[now][p][k]) update(((p<<1)-(1<<m))^1,p,k+1,k); if (j!=0) { for (int k=0;k<=d;k++) for (int p=(1<<(m-1));p<(1<<m);p++)//横放1*2,并且必须保证这个格子的上面那个格子放过了,前面的格子是空的; if (!(p&1)&&dp[now][p][k]) update(((p<<1)-(1<<m))^3,p,k,k); } for (int k=0;k<=d;k++) for (int p=0;p<(1<<(m-1));p++)//竖放1*2,并且必须保证这个格子的上面的格子是空的; if (dp[now][p][k]) update((p<<1)^1,p,k,k); } memset(dp[now],0,sizeof(dp[now])); now^=1; } int ans=0; for (int k=c;k<=d;k++) { ans+=dp[now][(1<<m)-1][k]; if (ans>=mod) ans-=mod; } } return 0; }
一层一层的转移:
#include <iostream> #include <stdio.h> #include <string.h> using namespace std; const int mod=1000000007; char s[110][12]; int n,m,c,d; int dp[110][1100][25]; void dfs(int i,int j,int k,int num,int p,int kk) { if (num>=m)//达到一种状态; { if(k+kk<=d) { dp[i+1][p][k+kk]+=dp[i][j][k]; if (dp[i+1][p][k+kk]>=mod) dp[i+1][p][k+kk]-=mod; } return; } if (j&(1<<num))//当前位置已放; { if (s[i+1][num]=='0') dfs(i,j,k,num+1,p+(1<<num),kk); else dfs(i,j,k,num+1,p,kk); return; } if (s[i+1][num]=='0') //放1*1 dfs(i,j,k,num+1,p+(1<<num),kk+1); else dfs(i,j,k,num+1,p,kk+1); if (num<m-1&&!(j&(1<<(num+1))))//横放1*2; { int pp=p; if (s[i+1][num]=='0') pp+=(1<<num); if (s[i+1][num+1]=='0') pp+=(1<<(num+1)); dfs(i,j,k,num+2,pp,kk); } if (s[i+1][num]=='1')//竖放1*2; dfs(i,j,k,num+1,p+(1<<num),kk); return; } int main() { // freopen("in.txt","r",stdin); while (~scanf("%d%d%d%d",&n,&m,&c,&d)) { for (int i=1;i<=n;i++) scanf("%s",s[i]); for (int i=0;i<m;i++) s[n+1][i]='0'; memset(dp,0,sizeof(dp)); int sum=(1<<m)-1; int p=0; for (int i=0;i<m;i++)//把最后一行的下面一行填满; if (s[1][i]=='0') p+=(1<<i); dp[1][p][0]=1; for (int i=1;i<=n;i++) { for (int j=0;j<=sum;j++) for (int k=0;k<=d;k++) if (dp[i][j][k]) { dfs(i,j,k,0,0,0); } } int ans=0; for(int i=c;i<=d;i++) { ans+=dp[n+1][sum][i]; if (ans>=mod) ans-=mod; } printf("%d\n",ans); } return 0; }
- HDU 4084 Campus Design 状压dp
- hdu 4804 Campus Design (状压dp)
- HDU 4804 Campus Design(状压DP)
- HDU 4804 Campus Design 状压DP
- HDU 4804 Campus Design(插头DP)
- hdu 4804 Campus Design(插头dp)
- HDU 4804 Campus Design 轮廓线DP
- hdu 4804 Campus Design 插头dp
- hdu 4804 Campus Design 轮廓线dp
- HDU 4804 Campus Design 轮廓线DP
- HDU 4804 Campus Design 轮廓线DP
- HDU 4804 Campus Design
- Hdu 4804 Campus Design
- Campus Design HDU
- hdu 4804 Campus Design (2013 南京 轮廓线dp)
- hdu 4804 Campus Design dp(记忆化搜索 /轮廓线 )
- HDU 4804 Campus Design(插头DP) (未理解)
- hdu4804 Campus Design 插头DP
- 递归删除文件,文件夹 linux
- jstl格式化日期标签
- Github for Windows使用图文教程
- eclipse的debug模式使用
- 下一代消费产品,穿戴式设备的理解
- HDU 4084 Campus Design 状压dp
- 一个成功的淘宝客网站具有哪些特点
- 程序调试--fprintf详解
- 《java解惑》读书笔记2——字符串之谜
- 调试代码
- python基础(1):文件的读取、创建、追加、删除、清空
- mysql"ON DUPLICATE KEY UPDATE"语法简析
- Java排序算法之快速排序
- 《30天自制操作系统》学习笔记--第10天