ACM: 动态规划题 poj&nb…

来源:互联网 发布:win7如何安装linux系统 编辑:程序博客网 时间:2024/06/05 20:21
Bugs Integrated,Inc.
Description
Bugs Integrated, Inc. is a majormanufacturer of advanced memory chips. They are launchingproduction of a new six terabyte Q-RAM chip. Each chip consists ofsix unit squares arranged in a form of a 2*3 rectangle. The wayQ-RAM chips are made is such that one takes a rectangular plate ofsilicon divided into N*M unit squares. Then all squares are testedcarefully 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 chipconsists of 2*3 (or 3*2) unit squares. Of course, no chip cancontain any bad (marked) squares. It might not be possible to cutthe plate so that every good unit square is a part of some memorychip. The corporation wants to waste as little good squares aspossible. Therefore they would like to know how to cut the plate tomake the maximum number of chips possible.
Task
You are given the dimensions of several silicon plates and a listof all bad unit squares for each plate. Your task is to write aprogram that computes for each plate the maximum number of chipsthat can be cut out of the plate.

Input

The first line of the input fileconsists of a single integer D (1 <= D<= 5), denoting the number of silicon plates. Dblocks follow, each describing one silicon plate. The first line ofeach block contains three integers N (1 <= N<= 150), M (1 <= M <=10), K (0 <= K <= MN) separated bysingle spaces. N is the length of the plate, M is its height and Kis the number of bad squares in the plate. The following K linescontain a list of bad squares. Each line consists of two integers xand y (1 <= x <= N, 1<= y <= M) ?coordinates of one badsquare (the upper left square has coordinates [1, 1], the bottomright is [N,M]).

Output

For each plate in the input fileoutput a single line containing the maximum number of memory chipsthat 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;
     elseQ[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;
}

0 0
原创粉丝点击