poj 1038 Bugs Integrated, Inc.三进制状压dp

4 篇文章 0 订阅
1 篇文章 0 订阅

http://poj.org/problem?id=1038
这题废了我n长时间
在这里插入图片描述
先把图片旋转下M为横轴N为纵轴
发现题目要求放2x3的方块,所以至少要存三行的状态,考虑三进制状压。

讨论状态

对于 ( x , y ) (x,y) (x,y)每一个三进制为
0 : ( x , y ) , ( x , y − 1 ) 0:(x,y),(x,y-1) 0:(x,y),(x,y1)都没有被占用
1 : ( x , y ) 1:(x,y) 1:(x,y)没有占用, ( x , y − 1 ) (x,y-1) (x,y1)被占用
3 : ( x , y ) 3:(x,y) 3:(x,y)被占用, ( x , y − 1 ) (x,y-1) (x,y1)可以不考虑
占用指的是:有坏点或被其他芯片覆盖
通过讨论 ( x , y ) (x,y) (x,y)来判断 ( x , y + 1 ) (x,y+1) (x,y+1)是否可能成为一个芯片的左上角
状态初始化全部为-1,代表不可到达

设置转移

d p [ i ] [ j ] dp[i][j] dp[i][j]表示第 i i i行状态 j j j时, 1 … i − 1 1…i-1 1i1行所能放芯片的最大数目
1、这一行的初始状态可以由下一行转移得来
下面 ( x , y − 1 ) , ( x , y ) , ( x , y + 1 ) (x,y-1),(x,y),(x,y+1) (x,y1),(x,y),(x,y+1)都表示这个坐标对应的状态
( x , y − 1 ) (x,y-1) (x,y1)为0, ( x , y ) (x,y) (x,y)为0
( x , y − 1 ) (x,y-1) (x,y1)为1, ( x , y ) (x,y) (x,y)为0
( x , y − 1 ) (x,y-1) (x,y1)为2, ( x , y ) (x,y) (x,y)为1
特别的当 ( x , y ) (x,y) (x,y)为坏点, ( x , y ) (x,y) (x,y)为2
2、开始dfs过程
参数 x x x表示所到达的列, i i i代表当前的行
( i , x ) (i,x) (i,x)放\不放芯片,讨论的都是 ( i , x ) (i,x) (i,x)作为左上角位置
p , q p,q p,q分别代表下一行和当前dfs的这一行

  1. ( i , x ) (i,x) (i,x)不放芯片,dfs直接跳转到 ( i , x + 1 ) (i,x+1) (i,x+1)
  2. ( i , x ) (i,x) (i,x)放竖着的芯片,前提 p [ x ] = 0 , p [ x + 1 ] = 0 , q [ x ] = 0 , q [ x + 1 ] = 0 p[x]=0,p[x+1]=0,q[x]=0,q[x+1]=0 p[x]=0,p[x+1]=0,q[x]=0,q[x+1]=0,当前已经枚举的放置个数+1转移到 d p [ i + 1 ] [ q ′ ] dp[i+1][q'] dp[i+1][q] q ′ q' q表示 q q q放置芯片后的状态 q [ x ] = q [ x + 1 ] = 2 q[x]=q[x+1]=2 q[x]=q[x+1]=2,dfs跳转到 ( i , x + 2 ) (i,x+2) (i,x+2)
  3. ( i , x ) (i,x) (i,x)放横着的芯片,前提 x ≤ m − 2 , q [ x ] = 0 , q [ x + 1 ] = 0 , q [ x + 2 ] = 0 x\le m-2,q[x]=0,q[x+1]=0,q[x+2]=0 xm2,q[x]=0,q[x+1]=0,q[x+2]=0,当前已经枚举的放置个数+1转移到 d p [ i + 1 ] [ q ′ ] dp[i+1][q'] dp[i+1][q] q ′ q' q表示 q q q放置芯片后的状态 q [ x ] = q [ x + 1 ] = q [ x + 2 ] = 2 q[x]=q[x+1]=q[x+2]=2 q[x]=q[x+1]=q[x+2]=2,dfs跳转到 ( i , x + 3 ) (i,x+3) (i,x+3)
    转移就结束了,详细的过程可以在代码中体现
#include <cstdio>
#include <cstring>
#include <iostream>
#define LL long long
using namespace std;
inline void read(int &x){
    x = 0; int f = 1; char ch = getchar();
    while (!(ch >= '0' && ch <= '9')){if (ch == '-') f = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}
    x *= f;
}
inline void Max(int &x, int y){if (y > x) x = y;}
int TT, n, m, k, ans, hit[151][11], f[2][59049], thr[11], p[11], q[11];
bool fg;
inline int make(int *a){//三进制转十进制
    int ret = 0;
    for (int i = 0; i < m; i++) ret += a[i + 1] * thr[i];
    return ret;
}
inline void res(int num, int *a){//十进制转三进制
    for (int i = 1; i <= m; i++) a[i] = num % 3, num /= 3;
}
inline void dfs(int x, int cnt){//x表示枚举到的列,cnt表示已经放置芯片的个数
    Max(ans, cnt);//更新ans
    Max(f[fg][make(q)], cnt);//更新当前q的状态值
    for (; x < m; x++){//通过循环省去转移方案1,也可以改为dfs(x+1,cnt),但更慢
    	//转移方案2
        if (p[x] == 0 && p[x + 1] == 0 && q[x] == 0 && q[x + 1] == 0){
            q[x] = q[x + 1] = 2;
            dfs(x + 2, cnt + 1);
            q[x] = q[x + 1] = 0;
        }
    	//转移方案3
        //这个位置写成else if好像也能ac,不知为何
        if (x <= m - 2 && q[x] == 0 && q[x + 1] == 0 && q[x + 2] == 0){
            q[x] = q[x + 1] = q[x + 2] = 2;
            dfs(x + 3, cnt + 1);
            q[x] = q[x + 1] = q[x + 2] = 0;
        }
    }
}
int main(){
	//预处理3的m次幂
    thr[0] = 1;
    for (int i = 1; i <= 10; i++) thr[i] = thr[i - 1] * 3;
    read(TT);
    while (TT--){
    	//hit表示坏点坐标
        memset(hit, 0, sizeof(hit)), memset(f, -1, sizeof(f));
        //fg用于滚动数组
        fg = 0; ans = 0;
        read(n), read(m), read(k);
        for (int i = 1, x, y; i <= k; i++) read(x), read(y), hit[x][y] = true;
        //预处理第一行,坏点为2,好点为1
        for (int i = 1; i <= m; i++) if (hit[1][i]) p[i] = 2; else p[i] = 1;
        f[1][make(p)] = 0;
        for (int i = 2; i <= n; i++){
        	//记得初始化
            memset(f[fg], -1, sizeof(f[fg]));
            for (int j = 0; j < thr[m]; j++) if (f[fg ^ 1][j] != -1){
                res(j, p);
                for (int o = 1; o <= m; o++){
                	//状态初始化见上
                    if (hit[i][o]) q[o] = 2;
                    else q[o] = max(0, p[o] - 1);
                }
                dfs(1, f[fg ^ 1][j]);
            }
            fg ^= 1;
        }
        printf("%d\n", ans);
    }
    return 0;
}

从这位dalao学来的%%%
http://www.cnblogs.com/dengeven/p/3237382.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值