博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
poj 1038 Bugs Integrated, Inc. 三进制状态压缩 DFS 滚动数组
阅读量:4322 次
发布时间:2019-06-06

本文共 4130 字,大约阅读时间需要 13 分钟。

  把底边贴着第 x 行底边放置的芯片 称为第 x 行芯片。

  由于芯片长度只有 3, 所以第 x 行芯片的放置只受 x-1行 和 x-2 行放置情况的影响。

  同时由于一旦 方格 (x-1, y)被黑色记号或其他芯片 占据,则方格(x-2,y)即便空闲对第 x行芯片的放置也毫无意义。

  所以,只需记录的状态只有:

    一, a[x] = 0  表示方格(x-1,y)空闲,方格(x-2,y)空闲

    二, a[x] = 1  表示方格(x-1,y)空闲,方格(x-2,y)被占据

    三, a[x] = 3, 表示方格(x-1,y)被占据

  意味着对于 I 层, 其状态 J, 保存着  I,I-1 层 芯片的放置方法,

  所以我们通过 dp(I,J)更新 I+1 层时,同样要更新 I+1 的状态信息 K, 其保存着 I+1, I层信息

  

  状态 dp(i,j)表示 前 i 层 状态为 J 的最大芯片数量

    情况一, 当前列y 不放,从 y+1 列开始考虑

    情况二, 当前两列 ( y, y+1 )  合法,放 3*2 芯片, 更新 I+1层状态 , 再去考虑 y+2列

    情况三, 当前三列(y,y+1,y+2)合法,放 2*3 芯片, 更新 I+1 层状态,再去考虑 y+3列

  这里因为  3^10 接近 60000,  又行数 n = 150,  因为只需要保存两层间关系,所以可以通过滚动数组来 优化空间。

  另,处理列的组合问题需要 递归DFS,通过回溯来解决。 另外,对于黑点,我们其实可以合并到 芯片占据的类型中去,

而不需要单独处理,这样就能同过 I层的放置序列 P(p1,p2,...,pm),I+1层的放置序列Q (Q1,Q2,。。,Qm),来决策了。

 

解题代码

View Code
#include
#include
#include
#include
const int N = 60000;int vis[155][11];int dp[2][60000], A[11], P[11], Q[11];int n, m, K, mask;inline int MAX(int a,int b){ return a>b?a:b;}int GetState( int f[] ){ int res = 0; for(int i = 1; i <= m; i++) res += (f[i]*A[i-1]); return res;}void GetBack( int x, int f[] ){ for(int i = 1; i <= m; i++) { f[i] = x%3; x /= 3; }}void dfs( int i, int x, int num) // 第i行,x列, 数量为num{ if( x > m ) return; int cur = (i+1)&1, nxt = i&1, k = GetState(Q) ; // 当前层可不放任意芯片 dp[nxt][k] = MAX( dp[nxt][k], dp[cur][ GetState(P) ] ); //情况(1) 当方格 (i+1,x) 不放置芯片时,那么考虑方格(i+1,x), 且 x < m //情况(2) 如果 P[x],P[x+1] = 0, 且区域 (i-1,i+1), (x,x+1)均无黑点 且 i >= 2 && x < m //则 竖立放置芯片 3*2, 左下角坐标为 (i+1,x) if( (x<=(m-1)) && ( (P[x]==0) && (P[x+1]==0) ) && ( (Q[x]==0)&&(Q[x+1]==0)) ) { Q[x] = Q[x+1] = 2; int kk = GetState(Q); dp[nxt][kk] = MAX( dp[nxt][kk], num+1 ); dfs( i, x+2, num+1 ); Q[x] = Q[x+1] = 0; } //情况(3) 如果 P[x],P[x+1],P[x+2] <= 1, 且区域 (i,i+1),(x,x+2) 均无黑点 且 i >= 1 && x < m-1 //则 横着放置芯片 2*3, 左下角坐标为 (i+1,x) if( (x<=(m-2)) && ( (!Q[x])&&(!Q[x+1])&&(!Q[x+2]) ) ) { Q[x]=Q[x+1]=Q[x+2] = 2; int kk = GetState(Q); dp[nxt][kk] = MAX( dp[nxt][kk], num+1 ); dfs( i, x+3, num+1); Q[x]=Q[x+1]=Q[x+2] = 0; } dfs( i, x+1, num ); }void solve(){ // 初始化为 -1,标明该 状态不可用 memset( dp, 0xff, sizeof(dp) ); memset( P, 0, sizeof(P)); memset( Q, 0, sizeof(Q)); for(int i = 1; i <= m; i++) P[i] = vis[1][i]+1; //损坏点看作 已占用。。 // 初始化第一层状态, 抽象把第0层看作皆被占用,合法状态仅一种,且方案数为0 dp[1][ GetState(P) ] = 0; mask = A[m]; // 0: i,i-1层位置皆为空 // 1:i层为空,i-1层已占用 // 2:i层已占用 for(int i = 2; i <= n; i++) { int cur = (i+1)&1, nxt= i&1; // 已知 dp(i,j) 状态j表示 i,i-1层 放置编号 // 初始化下一层nxt,初始时皆为不可用 memset( dp[nxt], 0xff, sizeof(dp[nxt]) ); for(int j = 0; j < mask; j++) { if( dp[cur][j] == -1 ) continue; //若当前状态不合法 //I层 放置编号J 解压成 放置序列 P[] GetBack( j, P ); //获取 I+1层 放置序列 Q[], 且把第I+1层 损坏位置看做已占用,添加到状态中 for(int x = 1; x <= m; x++) { if( vis[i][x] ) Q[x] = 2; else { //去除掉 I-1层 的信息,存储I,I+1放置信息 Q[x] = P[x]-1; if( Q[x] < 0 ) Q[x] = 0; } } // 获取第I+1行 放置状态以及数量 dfs( i, 1, dp[cur][j] ); //行i,列j,目前芯片数量 dp[cur][j] } } int ans = 0; for(int i = 0; i < mask; i++) ans = MAX( ans, MAX(dp[0][i],dp[1][i]) ); printf("%d\n", ans );}int main(){ freopen("test.in","r",stdin); freopen("mytest.out", "w", stdout); A[0] = 1; for(int i = 1; i <= 10; i++ ) A[i] = 3*A[i-1]; int T; scanf("%d", &T); while( T-- ) { scanf("%d%d%d", &n,&m,&K); int x, y; memset( vis, 0, sizeof(vis)); for(int i = 0; i < K; i++) { scanf("%d%d", &x,&y); vis[x][y] = 1; } solve(); } return 0;}

 

  

转载于:https://www.cnblogs.com/yefeng1627/archive/2013/01/15/2861786.html

你可能感兴趣的文章
uml系列(六)——行为图:活动&状态
查看>>
Learning Deconvolution Network for Semantic Segme小结
查看>>
Leetcode 424.替换后的最长重复字符
查看>>
第二阶段:2.商业需求文档MRD:1.M版本管理
查看>>
我爱Java系列---【单列集合和双列集合总结】
查看>>
新开始
查看>>
git - 如何从项目中删除git跟踪
查看>>
MacBook Air密码忘了,苹果电脑密码忘了怎么办
查看>>
PHP二维数组排序
查看>>
.Net Core WebApi返回的json数据,自定义日期格式
查看>>
C语言运算符表
查看>>
网络调试 adb connect
查看>>
ormlite 文档
查看>>
修改root远程ssh登录权限
查看>>
保存cookies
查看>>
iOS酷炫动画效果合集
查看>>
[CSS] Scale on Hover with Transition
查看>>
状压DP(挑战程序设计竞赛)
查看>>
POJ 2386
查看>>
腾讯云“动态加速”与“CDN”的区别——浅谈对“动态加速”的理解(可能有误)...
查看>>