poj 1038 Bugs Integrated, Inc.(状压dp)

http://poj.org/problem?id=1038

Bugs Integrated, Inc.
Time Limit: 15000MS Memory Limit: 30000K
Total Submissions: 8917 Accepted: 3404
Case Time Limit: 5000MS

Description

Bugs Integrated, Inc. is a major manufacturer of advanced memory chips. They are launching production of a new six terabyte Q-RAM chip. Each chip consists of six unit squares arranged in a form of a 2*3 rectangle. The way Q-RAM chips are made is such that one takes a rectangular plate of silicon divided into N*M unit squares. Then all squares are tested carefully and the bad ones are marked with a black marker. 

Finally, the plate of silicon is cut into memory chips. Each chip consists of 2*3 (or 3*2) unit squares. Of course, no chip can contain any bad (marked) squares. It might not be possible to cut the plate so that every good unit square is a part of some memory chip. The corporation wants to waste as little good squares as possible. Therefore they would like to know how to cut the plate to make the maximum number of chips possible. 
Task 
You are given the dimensions of several silicon plates and a list of all bad unit squares for each plate. Your task is to write a program that computes for each plate the maximum number of chips that can be cut out of the plate.

Input

The first line of the input file consists of a single integer D (1 <= D <= 5), denoting the number of silicon plates. D blocks follow, each describing one silicon plate. The first line of each block contains three integers N (1 <= N <= 150), M (1 <= M <= 10), K (0 <= K <= MN) separated by single spaces. N is the length of the plate, M is its height and K is the number of bad squares in the plate. The following K lines contain a list of bad squares. Each line consists of two integers x and y (1 <= x <= N, 1 <= y <= M) ?coordinates of one bad square (the upper left square has coordinates [1, 1], the bottom right is [N,M]).

Output

For each plate in the input file output a single line containing the maximum number of memory chips that can be cut out of the plate.

Sample Input

2
6 6 5
1 4
4 6
2 2
3 6
6 4
6 5 4
3 3
6 1
6 2
6 4

Sample Output

3
4

Source

题意:给一个N*M的矩形,问这个矩形中能放多少个2*3的矩形,还有个条件,有的点是坏点,坏点不能放矩形。

由于M<=10所以可以状压。三进制状态压缩,2表示这个点不能放,1表示这个点能放但它的上一个点不能放,0表示这个点能放且它的上一个点也能放。用这一行的状态推出后一行的状态,首先对于不放矩形的状态,如果这一行为2那么对应的下一行就是1,如果这一行为1那么对应的下一行为0,如果这一行为0那么下一行也为0。然后由下一行不放的状态推该行放矩形的状态,如果连续两个0与上一行对应的位置也是0,那么可以竖着放一个矩形,如果连续3个0,那么可以横着放矩形。由于存在坏点,我们还要判断矩形里是否有坏点。我们可以搜索出所有放矩形的状态进行更新。复杂度O(n*m*3^m)。在状压dp转移的时候,用dfs搜索有效状态进行更新也是一种不错的优化手段。代码如下:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<math.h>
#define nn 110000
#define inff 0x3fffffff
typedef long long LL;
using namespace std;
int n,m,k;
bool huai[200][20];
bool hu[200][20][200][20];
int dp[2][60000];
int po[20];
int w1[20],w2[20];
int ans,t;
void fuck(int x)
{
    for(int i=0;i<m;i++)
    {
        printf("%d",x%3);
        x/=3;
    }
    puts("");
}
bool check(int x1,int y1,int x2,int y2)
{
    int i,j,g,e;
    for(i=x1;i<=x2;i++)
    {
        for(j=y1;j<=y2;j++)
        {
            if(huai[i][j])
                return true;
        }
    }
    return false;
}
void init()
{
    int i,j,g,e;
    po[0]=1;
    for(i=1;i<=m;i++)
        po[i]=po[i-1]*3;
    memset(hu,false,sizeof(hu));
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            for(g=i;g<=n;g++)
            {
                for(e=j;e<=m;e++)
                {
                    hu[i][j][g][e]=check(i,j,g,e);
                }
            }
        }
    }
    for(i=0;i<=1;i++)
    {
        for(j=0;j<po[m];j++)
            dp[i][j]=-1;
    }
    dp[0][po[m]-1]=0;
}
void dfs(int id,int zt,int fc,int h)
{
    if(id==m)
        return ;
    int ix;
    if(id<m-1&&w2[id]==0&&w2[id+1]==0)
    {
        if(w1[id]==0&&w1[id+1]==0)
        {
            if(!hu[h-1][id+1][h+1][id+2])
            {
                ix=zt+2*po[id]+2*po[id+1];
                dp[1-t][ix]=max(dp[1-t][ix],fc+1);
                dfs(id+2,ix,fc+1,h);
            }
        }
        if(id<m-2&&w2[id+2]==0)
        {
            if(!hu[h][id+1][h+1][id+3])
            {
                ix=zt+2*po[id]+2*po[id+1]+2*po[id+2];
                dp[1-t][ix]=max(dp[1-t][ix],fc+1);
                dfs(id+3,ix,fc+1,h);
            }
        }
    }
    dfs(id+1,zt,fc,h);
}
void solve()
{
    int i,j,g,e;
    int ix,tem,fc;
    t=0;
    for(i=0;i<n;i++)
    {
        for(j=0;j<po[m];j++)
        {
            if(dp[t][j]<0)
                continue;
            ix=j,tem=0;
            for(g=0;g<m;g++)
            {
                w1[g]=ix%3;
                ix/=3;
                if(w1[g]==0)
                    w2[g]=0;
                else
                    w2[g]=w1[g]-1;
                tem+=w2[g]*po[g];
            }
            dp[1-t][tem]=max(dp[1-t][tem],dp[t][j]);
            dfs(0,tem,dp[t][j],i);
        }
        memset(dp[t],-1,sizeof(t));
        t=1-t;
    }
    ans=0;
    for(i=0;i<po[m];i++)
    {
        ans=max(ans,dp[t][i]);
    }
}
int main()
{
    int d,i;
    scanf("%d",&d);
    while(d--)
    {
        scanf("%d%d%d",&n,&m,&k);
        int u,v;
        memset(huai,false,sizeof(huai));
        for(i=1;i<=k;i++)
        {
            scanf("%d%d",&u,&v);
            huai[u][v]=true;
        }
        init();
        solve();
        printf("%d\n",ans);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值