POJ 2411 Mondriaan's Dream 轮廓线动态规划,插头dp,滚动数组
2017-09-16 21:15
375 查看
原题链接
设矩阵共m列,n行,设当前状态为k
d[i][j][k]:当前格子坐标为(i,j),之前的连续m个格子的状态为k
状态转移:
①若k最高位为1,可以不放
②若k最高位为0,可以朝上竖着放
③若k最高位为1,可以向朝左横着放
注:
①初始状态说明:
d[(1<<m)-1]=1 (*)
当首次循环,i=j=0,设第0行之前有一虚拟行,则初始状态即(设m=4):
(当前格子用p表示)
1 1 1 1
p (第0行)
则此状态唯一可行的决策是不放,故有:d[0][0][1110]=d[初始状态][1111]=1
则第二次循环,即i=0,j=1,则对于满足如下状态:
1 k1 k2
0 p (第0行)
的所有状态k有唯一决策(设新状态为k'):横放,即d[0][1][k']=sigma(d[0][0][k] | k为满足以上状态的所有状态)
已知,对于一行两列的矩阵,合法摆放应该只有一种,所以d[0][1][k']=1,又仅当k为1110时才有值1,其它满足条件的k的d值均为0,所以若按此(*式)设置初始状态,则正好满足条件。而对于1行1列的特殊状态,即d[0][0][1111],仍为0,也符合事实。这是初始状态设置的原因。
②对于已经确定当前k的最高位为1的状态(转移1、3),那么k<<1的最高位也为1,所以清除新的溢出位(第m+1位)k应使用异或:(k<<1)^(1<<m)。
③本题使用滚动数组减少空间占用,详见滚动数组说明:滚动数组的应用。
代码:
设矩阵共m列,n行,设当前状态为k
d[i][j][k]:当前格子坐标为(i,j),之前的连续m个格子的状态为k
状态转移:
①若k最高位为1,可以不放
②若k最高位为0,可以朝上竖着放
③若k最高位为1,可以向朝左横着放
注:
①初始状态说明:
d[(1<<m)-1]=1 (*)
当首次循环,i=j=0,设第0行之前有一虚拟行,则初始状态即(设m=4):
(当前格子用p表示)
1 1 1 1
p (第0行)
则此状态唯一可行的决策是不放,故有:d[0][0][1110]=d[初始状态][1111]=1
则第二次循环,即i=0,j=1,则对于满足如下状态:
1 k1 k2
0 p (第0行)
的所有状态k有唯一决策(设新状态为k'):横放,即d[0][1][k']=sigma(d[0][0][k] | k为满足以上状态的所有状态)
已知,对于一行两列的矩阵,合法摆放应该只有一种,所以d[0][1][k']=1,又仅当k为1110时才有值1,其它满足条件的k的d值均为0,所以若按此(*式)设置初始状态,则正好满足条件。而对于1行1列的特殊状态,即d[0][0][1111],仍为0,也符合事实。这是初始状态设置的原因。
②对于已经确定当前k的最高位为1的状态(转移1、3),那么k<<1的最高位也为1,所以清除新的溢出位(第m+1位)k应使用异或:(k<<1)^(1<<m)。
③本题使用滚动数组减少空间占用,详见滚动数组说明:滚动数组的应用。
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int k,n,m,cur; long long d[2][1<<15]; void update(int a,int b){d[cur][b]+=d[1-cur][a];} ///a:former k, b:current k, k' ///d[i][j][s]: the maximum setting plans when at cell(i,j), ///and the state of m continuous cells ended with cell(i,j) is s int main(){ while(scanf("%d%d",&n,&m)){ if(m==0&&n==0) break; if(n<m) swap(n,m); memset(d,0,sizeof(d)); cur=0; d[0][(1<<m)-1]=1; for(int i=0;i<n;i++) for(int j=0;j<m;j++){ cur^=1; memset(d[cur],0,sizeof(d[cur])); for(int k=0;k<(1<<m);k++){ ///assume former k->k, current k->k' if(k&(1<<(m-1))) update(k,(k<<1)^(1<<m));///not set ///condition: the highest bit(m th, count from 1) of k is 1, if(i&&!(k&(1<<(m-1)))) update(k,(k<<1)^1);///set upward ///condition: the highest bit (m th) of k is 0, and i>0 if(j&&!(k&1)&&(k&(1<<(m-1)))) update(k,(k<<1)^3^(1<<m));///set leftward ///condition: the highest bit (m th) of k is 1, the lowest bit of k is 0 } ///in every repeating, the highest bit of former k will be filled with 1, so in the end, ///every cell in the first (n-1) rows will be filled with 1, so if the last row(n th) is filled with 1 ((1<<m)-1), ///current state will be the answer } printf("%lld\n",d[cur][(1<<m)-1]); } }
相关文章推荐
- POJ-2411-Mondriaan's Dream-轮廓线dp(插头dp)
- POJ 2411 Mondriaan's Dream(插头DP,轮廓线)
- T解 POJ-2411 Mondriaan's Dream [轮廓线DP] || [状压DP]
- POJ2411——Mondriaan's Dream(轮廓线dp入门)
- POJ 2411 Mondriaan's Dream [插头DP做法]
- poj2411 Mondriaan's Dream【插头dp】
- POJ 2411 Mondriaan's Dream (轮廓线DP代码详解)
- POJ 2411 (动态规划-状压DP AND 轮廓线DP)
- poj2411 Mondriaan's Dream 插头dp做法
- poj - 2411 - Mondriaan's Dream(轮廓线dp)
- [POJ] 2411 Mondriaan's Dream [轮廓线dp]
- POJ-2411 Mondriaan's Dream(轮廓线dp)
- poj_2411 Mondriaan's Dream(轮廓线dp)
- poj 2411 Mondriaan's Dream 轮廓线dp
- POJ 2411 Mondriaan's Dream 轮廓线DP
- poj2411 Mondriaan's Dream(轮廓线dp)
- poj-2411 Mondriaan's Dream (状态压缩dp)
- poj 2411 Mondriaan's Dream(状压dp)
- poj 2411/hdu 1400 Mondriaan's Dream 状态压缩dp
- POJ 2411 Mondriaan's Dream (状压dp)