POJ 1038 状压DP

一个公司生产一种2*3规模的芯片,但是原材料上面有一些地方是不能用来当作芯片材料的,给出原料大小,及上面不能做原料的点,问你怎么分解,可以使生成芯片最大化。

对M进行三进制状压

last数组存储第i-1行和i-2行状态,cur数组存储i行和i-1行状态

cur[k]=2; // 本行k位置和上行k位置都不可用

cur[k]=1; // 本行k位置可用,上行k位置不可用

cur[k]=0; // 本行和上行位置k均可用

必须用滚动数组,否则爆内存

#include "stdio.h"
#include "string.h"

int b[20],ans,n,m;
int dp[2][69050],last[21],cur[21],map[160][160];

int updata(int i,int j)
{
    int res,k;
    res=0;
    memset(cur,0,sizeof(cur));
    memset(last,0,sizeof(last));

    for (k=1;k<=m;k++)
    {last[k]=j%3; j/=3;}

    for (k=1;k<=m;k++)
    if (map[i][k]==1)
    {
        cur[k]=2; // 本行k位置和上行k位置都不可用
        res+=b[k]*2;
    }else
    if (last[k]==2) // 上一行 k位置被占,上上行k位置没有被占
    {
        cur[k]=1; // 本行k位置可用,上行k位置不可用
        res+=b[k];
    }
    else
        cur[k]=0; // 本行和上行位置k均可用

    return res; // 本行位置压缩值
}

void dfs(int i,int now,int k,int status) // 第i行,价值为now,当前放第k个,状压值status
{
    int temp;
    if (now>ans) ans=now;
    if (now>dp[i][status]) dp[i][status]=now;
    if (k+1<=m && cur[k]==0 && cur[k+1]==0 && last[k]==0 && last[k+1]==0)  // 本行,上行,上上行的k和k+1位置均可用
    {
        cur[k]=2;
        cur[k+1]=2;
        temp=status+b[k]*2+b[k+1]*2;
        dfs(i,now+1,k+2,temp);
        cur[k]=0;
        cur[k+1]=0;
    }// 放置3行*2列 矩阵

    if (k+2<=m && cur[k]==0 && cur[k+1]==0 && cur[k+2]==0) // 本行,上行的k和k+1,k+2位置均可用
    {
        cur[k]=cur[k+1]=cur[k+2]=2;
        temp=status+b[k]*2+b[k+1]*2+b[k+2]*2;
        dfs(i,now+1,k+3,temp);
        cur[k]=cur[k+1]=cur[k+2]=0;
    } // 放置2行*3列 矩阵

    if (k+1<=m) dfs(i,now,k+1,status);
}
int main()
{
    int i,Case,k,aim,status,j,x,y;

    b[0]=0;
    b[1]=1;
    for (i=2;i<=11;i++)
        b[i]=b[i-1]*3;

    scanf("%d",&Case);
    while (Case--)
    {
        scanf("%d%d%d",&n,&m,&k);
        memset(map,0,sizeof(map));
        while (k--)
        {
            scanf("%d%d",&x,&y);
            map[x][y]=1;
        }
        aim=b[m+1]-1;
        status=0;
        for (i=1;i<=m;i++)
            if (map[1][i]==1) status+=2*b[i];
            else status+=b[i];

        memset(dp,-1,sizeof(dp));
        dp[1][status]=0;
        ans=0;
        for (i=2;i<=n;i++)
        {
            memset(dp[i%2],-1,sizeof(dp[i%2]));
            for (j=0;j<=aim;j++)
                if (dp[1-i%2][j]!=-1)
                {
                    status=updata(i,j);
                    dfs(i%2,dp[1-i%2][j],1,status);
                }
        }
        printf("%d\n",ans);

    }
    return 0;

}

POJ 1038 状压DP

时间: 2024-12-14 11:13:36

POJ 1038 状压DP的相关文章

西电oj 1038 状压dp

西电oj 1038  状压dp 1038: 裁玻璃 时间限制: 1 Sec  内存限制: 128 MB提交: 33  解决: 4[提交][状态][讨论版] 题目描述 张老板的玻璃店开张了,生意火爆.今天,隔壁玻璃店的刘老板拿来一块玻璃,意在刁难张老板.刘老板说:“我这块玻璃是由N(行)*M(列)小正方形玻璃拼成的,但是其中有一些玻璃坏了,我希望你现在把它裁成尽量多的2*2的小玻璃,而且这些小玻璃都不能有坏的地方.如果你裁出来的块数不是最多的,我就把你赶出建材市场.”现在,张老板来拜托你帮他解决这

POJ 3254 (状压DP) Corn Fields

基础的状压DP,因为是将状态压缩到一个整数中,所以会涉及到很多比较巧妙的位运算. 我们可以先把输入中每行的01压缩成一个整数. 判断一个状态是否有相邻1: 如果 x & (x << 1) 非0,说明有相邻的两个1 判断一个状态能否放在该行: 如果 (a[i] & state) != state,说明是不能放置的.因为a[i]中存在某个0和对应state中的1,与运算之后改变了state的值 判断相邻两行的状态是否有同一列相邻的1: 如果(state & _state)不

Best Sequence(poj 1699) 状压dp(TSP)

类似于前两天做的那个wordstack.状压的其实有时候爆搜+记忆化也差不多. 就是这个是要与之前的都重合,移位预处理要注意. 理解好第一个样例就行 /* *********************************************** Author :bingone Created Time :2014/12/9 22:48:56 File Name :a.cpp ************************************************ */ #inclu

POJ 3254 状压DP

题目大意: 一个农民有一片n行m列 的农场   n和m 范围[1,12]  对于每一块土地 ,1代表可以种地,0代表不能种. 因为农夫要种草喂牛,牛吃草不能挨着,所以农夫种菜的每一块都不能有公共边. 告诉你 n ,m 和那些地方能种菜哪些地方不能种菜,求农夫一共有多少种方案种菜 解法: 基本思想是状压 也就是用一个int 型的数代表一行的种菜策略,二进制的0代表该位不能种菜,1位代表能种菜,使用位运算使处理速度变快 对于单行行,最多有2^12 种情况,并且 2^12种情况里面还有很多不满足题意的

POJ 2411 状压DP经典

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 16771   Accepted: 9683 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

POJ 2686(状压DP

第一次做状压感觉那一长串for显示了这是个多么暴力的算法呢...1A了倒是挺顺的 #include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<utility> #include<vector> #include<cstring> #include<cmath> #define INF 0x3fffffff #d

poj 3254 状压dp入门题

1.poj 3254  Corn Fields    状态压缩dp入门题 2.总结:二进制实在巧妙,以前从来没想过可以这样用. 题意:n行m列,1表示肥沃,0表示贫瘠,把牛放在肥沃处,要求所有牛不能相邻,求有多少种放法. #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #d

poj 2923 状压dp+01背包

好牛b的思路 题意:一系列物品,用二辆车运送,求运送完所需的最小次数,两辆车必须一起走 解法为状态压缩DP+背包,本题的解题思路是先枚举选择若干个时的状态,总状态量为1<<n,判断这些状态集合里的那些物品能否一次就运走,如果能运走,那就把这个状态看成一个物品.预处理完能从枚举中找到tot个物品,再用这tol个物品中没有交集(也就是两个状态不能同时含有一个物品)的物品进行01背包,每个物品的体积是state[i],价值是1,求包含n个物品的最少价值也就是dp[(1<<n)-1](dp

POJ 2411 状压dp

题目大意: 用 1*2 或者2 *1的木板填满 h*w的长方形,问总共有多少种填充方法 直接dfs会超时,因为后面答案甚至爆了int,直接搜,肯定也是long long 的时间复杂度 这里我们将当前位置没放置任何木板为 0 , 如有放置则看为 1 每次通过当前行 i 的状态 old 找到下一行 i + 1 所有满足当前行状态的状态 new , 将 dp[i+1][new] += dp[i][old] 这个new的状态一定会在old状态为 0 的位置为1 , 因为上一行为 0 , 说明是留给竖木板