ACM: 动态规划题 poj&nb…

Bugs Integrated, Inc.
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.
ACM: <wbr>动态规划题 <wbr>poj <wbr>1038 <wbr>状态压缩

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

 

题意: 在一个矩形框内, 放置芯片2*3或3*2大小, 但是矩形框内有黑点, 不能放置的方格.

      每个方格1*1大小. 计算最大放置芯片的数量.

 

解题思路:

     1. 其实题目不难, 只要懂得状态压缩. 不过这次状态是用三进制.

        状态压缩:

          (1). 将每一行看成一个整体, 每一位表示一个方格的状态. 因为问题中要求

               放置的的芯片大小是2*3 or 3*2. 设a[x]: 表示一行中横坐标为x的状态.

               情况有三种: y表示行, x表示列

               1). 当(x,y)空白, 并且(x,y-1)空白 a[x] = 0;

               2). 当(x,y-1)被占用, (x,y)空白 a[x] = 1;

               3). 当(x,y)和(x,y-1)都被占用 a[x] = 2;

               这样我们用一个a[x1]a[x2]a[x3]...a[xm]这样的三进制序列, 用一个十进制

               数表示 P(放置编号).

          (2). 设状态方程dp[i][j]: 表示前i层放置编号j的最大芯片数量. 这样我们可以用

               当前一行来推出下一行的放置情况.

               Q[i] = (p[i] == 0 ? 0 : p[i]-1);  

               例: 当p[i] = 1, 表示当前行横坐标i为(i,y)空闲, (i,y-1)被占用.

                   在下一行看来是(i,y)空闲, (i,y+1)空闲. Q[i] = 0;

          (3). 接下来是状态转移方程, 同样分成三种情况:

               1). 方格(i,x)不放置芯片, 转移到(i, x+1)讨论.

               2). 竖直放置3*2时, p[i] == 0 && p[i+1] == 0 && Q[i] == 0 && Q[i+1] == 0

                   这样可以竖直放置一个芯片, 状态j = j+(2*3^i)+(2*3^i+1), 下一个考虑的

                   位置是(i,x+2).

               3). 水平放置2*3时, p[t] <= 1 && p[t+1] <= 1 && p[t+2] <= 1
                                  && Q[t] == 0 && Q[t+1] == 0 && Q[t+2] == 0

                   这样可以水平放置一个芯片, 状态j = j+(2*3^i)+(2*3^(i+1))+(2*3^(i+2))

                   下一个考虑的位置是(i,x+3).

     2. 接下来就是范围的确定, 大概3^10 = 59049这个是状态的数量(上界). 时间复杂度O(n*m*3^m)

        最大150*10*59049 = 88573500. 题目给15S还是可以接受的. 加上滚动数组可以节省空间.

 

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 59055 //3^10 = 59049
#define MAXSIZE 152

int n, m, K;
int g[MAXSIZE][12], p[12], Q[12];
int dp[2][MAX], e, num;
int result;

inline int max(int a, int b)
{
 return a > b ? a : b;
}

inline int getState(int *p, int n)
{
 int state = 0;
 for(int i = 1; i <= n; ++i)
  state = state*3 + p[i];
 return state;
}

inline void getCode(int *p, int n, int state)
{
 int i;
 for(i = n; i >= 1; --i)
 {
  p[i] = state%3;
  state /= 3;
 }
}

void DP(int j, int *p, int *Q, int ans)
{
 dp[e][ getState(Q, m) ] = max(dp[e][ getState(Q, m) ], ans);
 result = max(result, ans);
 for(int t = j; t <= m; ++t)
 {
  if(t >= m) return ;

  //竖放3*2
  if(t+1 <= m && p[t] == 0 && p[t+1] == 0 && Q[t] == 0 && Q[t+1] == 0)
  {
   Q[t] = Q[t+1] = 2;
   DP(j+2, p, Q, ans+1);
   Q[t] = Q[t+1] = 0;
  }//横放2*3
  else if( t+2 <= m && p[t] <= 1 && p[t+1] <= 1 && p[t+2] <= 1
   && Q[t] == 0 && Q[t+1] == 0 && Q[t+2] == 0)
  {
   Q[t] = Q[t+1] = Q[t+2] = 2;
   DP(j+3, p, Q, ans+1);
   Q[t] = Q[t+1] = Q[t+2] = 0;
  }
 }
}

int main()
{
 int i, j, k;
// freopen("input.txt", "r", stdin);
 int caseNum;
 scanf("%d", &caseNum);
 while(caseNum--)
 {
  scanf("%d %d %d", &n, &m, &K);
  memset(dp, -1, sizeof(dp));
  memset(g, 0, sizeof(g));
  int x, y;
  for(i = 0; i < K; ++i)
  {
   scanf("%d %d", &x, &y);
   g[x][y] = 1;
  }

  num = 1;
  for(i = 1; i <= m; ++i)
  {
   num *= 3;
   p[i] = g[1][i]+1; //第一行的上一行是全部为黑点
  }

  dp[0][ getState(p, m) ] = 0;
  e = 0, result = 0;
  for(i = 1; i < n; ++i)
  {
   e ^= 1;
   memset(dp[e], -1, sizeof(dp[e]));
   for(j = 0; j < num; ++j)
   {
    if( dp[e^1][j] == -1 ) continue;
    getCode(p, m, j); //j -> p[1...m];
    for(k = 1; k <= m; ++k)
    {
     if(p[k] == 0) Q[k] = 0;
     else Q[k] = p[k]-1;
     if( g[i+1][k] == 1 ) Q[k] = 2;
    }

    DP(1, p, Q, dp[e^1][j]);
   }
  }

  printf("%d\n", result);
 }

 return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值