首页 > 代码库 > POJ 1038 Bugs Integrated, Inc.

POJ 1038 Bugs Integrated, Inc.

Bugs Integrated, Inc.
Time Limit: 15000MS Memory Limit: 30000K
Total Submissions: 8825 Accepted: 3381
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

CEOI 2002

题意:给定长*宽的格子,其中有的点是不可用的,求这些格子,能组成的2*3 或3*2 的格子的最大数量

     这题总共做了三天,第一天看到这个题目的时候,注意到他的M非常小,可以用状态压缩dp 做,但是没有思路,第一天晚上的时候想到用三进制能够处理,于是第二天打出了用三进制压缩的代码,结果在调试的时候发现,有bug存在,无论怎么弥补,一直到晚上都是wa,我无法进行处理,晚上回到宿舍突然想到了四进制,画图发现,四进制的思路非常清晰,满怀信心的等天亮,用四进制来实现,结果这次却是tle,原因是用四进制压缩,状态太多,有些灰心了,原本以为四进制也要破产了,准备回归三进制了,结果偶然间想到中间一个过程可以优化,优化:提前处理出能相互满足的状态来。这样循环的次数大幅度减少,终于迎来了AC。

四进制思路:
三个状态 0 1 2 3
0 代表相应的格子不放,他的上一行对应的格子可以是0 1 2
1代表放2*3的格子  对应的上一行的格子必须是0
2 代表放3*2的格子 对应上一行的格子必须是3
3: 代表在他的下边一行可以放3*2的格子,3本身也代表不放,3处在3*2格子的中间位置,他所对应的上一行的格子必须是0
   这样对应的下一行格子在是2的时候,上一行对应的格子是3, 3对应的上一行的格子是0。而3 0 都是不放的,3*2的格子就可以放  了。
   下面是可能的一种状态便于理解。
......................
2 2 0 0 0 1 1 1
0 0 0 3 3 0 0 0      
1 1 1 2 2 1 1 1
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#define N 200
using namespace std;
int status[N*10],a[N],b[N/10],dp[N][N*10],map[N][N];
int cou[N*10];
struct num
{
    int y,next;
}d[N*10*N*10];
int e[N*10];
int n,m,k,Top,bian;
int main()
{
    //freopen("data.txt","r",stdin);
    void pre_dp();
    int get_dp();
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d %d",&n,&m,&k);
        Top = 0;
        memset(map,0,sizeof(map));
        for(int i=1;i<=k;i++)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            map[x][y-1] = 1;
        }
        pre_dp();
        int ans = get_dp();
        printf("%d\n",ans);
    }
    return 0;
}
int get_dp()
{
    for(int i=2;i<=n;i++)
    {
        for(int j=0;j<=Top-1;j++)
        {
            int val = status[j];
            bool ch = true;
            for(int u=0;u<=m-1;u++)
            {
                a[u] = val%4;
                val = val/4;
                if(a[u]!=0&&(map[i][u]||map[i-1][u]))
                {
                    ch = false;
                    break;
                }
                if(a[u]==2)
                {
                    if(i<=2||(i>2&&map[i-2][u]))
                    {
                        ch = false;
                        break;
                    }
                }
            }
            if(!ch)
            {
                continue;
            }
            for(int wb=e[j];wb!=-1;wb=d[wb].next)    //优化,提前处理好满足的情况,否则超时
            {
                int u = d[wb].y;
                dp[i][j] = max(dp[i][j],dp[i-1][u]);
            }
            dp[i][j]+=cou[j];
        }
    }
    int ans = 0;
    for(int i=0;i<=Top-1;i++)
    {
        ans = max(ans,dp[n][i]);
    }
    return ans;
}
void addeage(int x,int y)
{
    d[bian].y = y;
    d[bian].next = e[x];
    e[x] = bian++;
}
void pre_dp()
{
    int sum = 1;
    for(int i=1;i<=m;i++)
    {
        sum = sum*4;
    }
    sum-=1;
    memset(cou,0,sizeof(cou));
    for(int i=0;i<=sum;i++)                 //求出满足的所有的四进制状态即:三个连续1,两个连续2或3
    {
        int val = i;
        for(int j=0;j<=m-1;j++)
        {
            a[j] = val%4;
            val = val/4;
        }
        bool ch = true;
        int ds = 0;
        for(int j=0;j<=m-1;)
        {
            if(a[j]!=0)
            {
                if(a[j]==1&&(j+2)<=m-1&&a[j+1]==1&&a[j+2]==1)
                {
                    j+=3;
                    ds++;
                }else if(a[j]==2&&(j+1)<=m-1&&a[j+1]==2)
                {
                    j+=2;
                    ds++;
                }else if(a[j]==3&&(j+1)<=m-1&&a[j+1]==3)
                {
                    j+=2;
                }else
                {
                    ch = false;
                    break;
                }
            }else
            {
                j++;
            }
        }
        if(ch)
        {
           cou[Top] = ds;
           status[Top++] = i;
        }
    }
    memset(dp,0,sizeof(dp));
    memset(e,-1,sizeof(e));
    bian = 0;
    int asum = 0;
    for(int i=0;i<=Top-1;i++)                  //优化步骤
    {
        int val = status[i];
        for(int j=0;j<=m-1;j++)
        {
            a[j] = val%4;
            val= val/4;
        }
        for(int j=0;j<=Top-1;j++)
        {
            val = status[j];
            bool ch = true;
            for(int u=0;u<=m-1;u++)
            {
                b[u] = val%4;
                val = val/4;
                if(a[u]==1&&b[u]==0)
                {

                }else if(a[u]==2&&b[u]==3)
                {

                }else if(a[u]==3&&b[u]==0)
                {

                }else if(a[u]==0&&(b[u]==1||b[u]==2||b[u]==0))
                {

                }else
                {
                    ch = false;
                    break;
                }
            }
            if(ch)
            {
                addeage(i,j);
            }
        }
    }

}