POJ 1038 Bugs Integrated, Inc.(状态压缩)

Bugs Integrated, Inc.

Time Limit: 15000MS   Memory Limit: 30000K
Total Submissions: 9088   Accepted: 3472
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

题意简述:  一个生产芯片的工厂要生产一种规格为2X3的芯片,方法是先产生一块规格为nXm的矩形硅片,有nXm个正方形方块组成,但是硅片上存在一些损坏的方块,显示为黑色,它们不能用来制作芯片。现在给出硅片上每个损坏方块的位置,求用该硅片最多能切割出多少块芯片。

思路:  要知道能否存在第k-2行至第k行这3行中切割出芯片及切出多少芯片,需要知道这3行上每个方块的具体状态:是否损坏,是否已经被其他芯片使用,这两种情况都称为不可用。那么可以用一个三进制数来表示某一列第k-1至第k行的状态:0表示两个方块都可用,1表示仅有第k-1行的方块可用,2表示第k行的方块不可用。

  用dp[k][t]表示第k-1行至第k行所有列的三进制特征数分别等于三进制数t的每一位的状态下最多能够切割出的芯片数。那么在状态转移时,凭借上一层的状态和本层的状态就能够知道这3行的全部情况。

  该题中父状态和子状态都是多对多的关系,应该对每个可行的子状态(有些状态时不可用形成的),求切割父状态并更新它的最大值。
 1 #include<cstdio>
 2 int map[155][15];
 3 int tri[12]={0,1,3,9,27,81,243,729,2187,6561,19683,59049};
 4 int dp[2][59049];//用滚动数组记录每一行的状态
 5 int pre[15],now[15];//上一行与本行的三进制状态
 6 int n,m;
 7 int max(int a,int b)
 8 {
 9     return (a>=b)?a:b;
10 }
11 int getten(int a[])//把三进制状态转化为十进制数
12 {
13     int sum=0;
14     for(int i=1;i<=m;++i)
15         sum+=tri[i]*a[i];
16     return sum;
17 }
18 void gettri(int k,int a[])//把十进制数转化为三进制数
19 {
20     for(int i=1;i<=m;i++)
21     {
22         a[i]=k%3;
23         k=k/3;
24     }
25     return;
26 }
27 void dfs(int i,int j,int last,int key)
28 {
29     int k;
30     dp[i%2][key]=max(dp[i%2][key],last);//不做改动,更新父状态
31     if(j>=m)
32         return;
33     if(!pre[j] && !pre[j+1] && !now[j] && !now[j+1])//竖着切割
34     {
35         now[j]=now[j+1]=2;
36         k=getten(now);
37         dfs(i,j+2,last+1,k);
38         now[j]=now[j+1]=0;
39     }
40     if(j<m-1 && !now[j] && !now[j+1] && !now[j+2])
41     {
42         now[j]=now[j+1]=now[j+2]=2;
43         k=getten(now);
44         dfs(i,j+3,last+1,k);
45         now[j]=now[j+1]=now[j+2]=0;
46     }
47     dfs(i,j+1,last,key);//不做改动,深搜下一列
48     return;
49 }
50 int main()
51 {
52     int nn,k,a,b,tmp,ans;
53     scanf("%d",&nn);
54     while(nn--)
55     {
56         scanf("%d %d %d",&n,&m,&k);
57         for(int i=0;i<tri[m+1];++i)
58             dp[1][i]=-1;//先初始化第一行的全部状态都是不可能形成的
59         for(int i=1;i<=m;++i)
60             for(int j=1;j<=n;++j)
61                 map[j][i]=0;
62         for(int i=1;i<=k;++i)
63         {
64             scanf("%d %d",&a,&b);
65             map[a][b]=1;
66         }
67         for(int i=1;i<=m;++i)
68             pre[i]=map[1][i]+1;//计算第一行的状态第0行的方块全部视为不可用
69         tmp=getten(pre);
70         dp[1][tmp]=0;//设置第一行的原本状态时可以形成的,状态值为0
71         for(int i=2;i<=n;++i)//枚举子状态
72         {
73             for(int j=0;j<tri[m+1];++j)
74                 dp[i%2][j]=-1;//先设置父状态值为-1,等待更新
75             for(int j=0;j<tri[m+1];++j)
76             {
77                 if(dp[(i+1)%2][j]==-1)//跳过不可能的子状态
78                     continue;
79                 gettri(j,pre);
80                 for(int t=1;t<=m;++t)
81                 {
82                     if(map[i][t])
83                         now[t]=2;
84                     else
85                         now[t]=max(pre[t]-1,0);
86                 }//根据上一行的状态得到本行的状态
87                 tmp=getten(now);
88                 dfs(i,1,dp[(i+1)%2][j],tmp);//深搜这一层所有可能的状态
89             }
90         }
91         ans=0;
92         for(int i=0;i<tri[m+1];++i)
93             ans=max(ans,dp[n%2][i]);//得到结果
94         printf("%d\n",ans);
95     }
96     return 0;
97 }
时间: 2024-10-28 10:58:40

POJ 1038 Bugs Integrated, Inc.(状态压缩)的相关文章

POJ 1038 Bugs Integrated, Inc. 状态压缩DP

题目来源:1038 Bugs Integrated, Inc. 题意:最多能放多少个2*3的矩形 思路:状态压缩DP啊 初学 看着大牛的代码搞下来的  总算搞懂了 接下来会更轻松吧 3进制代表前2行的状态(i行和i-1行)1代表i-1行占位 2代表i行占位 i-1不管有没有占位都不会影响的0代表i行和i-1行都空闲 然后枚举状态dfs更新状态 话说就不能没写深搜了 有点不会了 #include <cstdio> #include <cstring> #include <alg

CEOI 2002, POJ 1038 Bugs Integrated, Inc. 状态压缩 DP

有点点小虐心. #include <iostream> #include <cstring> #include <fstream> using namespace std; const int ternarys[12] = { 0, 1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049 }; int DP[2][59049]; int bit_map[155][15]; int pre_line[15]; int now

POJ 1038 Bugs Integrated Inc (复杂的状压DP)

\(POJ~1038~~*Bugs~Integrated~Inc:\) (复杂的状压DP) \(solution:\) 很纠结的一道题目,写了大半天,就想练练手,结果这手生的.其实根据之前那道炮兵阵地就不应该写的,但是总觉得自己的思路会好一些,码量又小. 博主的核心思路其实就是用一个二进制数来压缩三行的状态,因为二进制的左移右移很方便.然后就是如果三进制会很不好转移. 我们可以用一个二进制数来预处理压缩出第 \(i\) 往下三行的障碍状态,前 \(m\) 个二进制位表第 \(i\) 行,中间 \

POJ 1038 Bugs Integrated, Inc.

AC通道 神坑的一道题,写了三遍. 两点半开始写的, 第一遍是直接维护两行的二进制.理论上是没问题的,看POJ discuss 上也有人实现了,但是我敲完后准备开始调了.然后就莫名其妙的以为会超时,就删掉了. 第二遍是想错了,因为和之前写过的一道题很像,那道题的正方形最中间不重合即可,所以我以为本质是一样的,然后按照那样的思路写.写写调调到五点半,样例搞掉后,提交,A2T7W1 然后随便找了组数组跟了一下,发现这个方块不允许重合导致这两道题的核心思路差别很大,所以删掉了. 第三遍开始按照自己想的

POJ 1038 Bugs Integrated, Inc. ——状压DP

状压上面有几个方块,然后DFS转移. 复杂度貌似很高$3_{}^{20}*n$ 反正过了 #include <map> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i)

poj 3254 Corn Fields ,状态压缩DP

题目链接 题意: 一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相邻.问有多少种放牛方案(一头牛都不放也是一种方案) state[i] 表示对于一行,保证不相邻的方案 状态:dp[i][ state[j] ]  在状态为state[j]时,到第i行符合条件的可以放牛的方案数 状态转移:dp[i][ state[j] ] =Sigma dp[i-1][state'] (state'为符合条

[POJ 2411] Mondriaan&#39;s Dream 状态压缩DP

题意 给定一个 n * m 的矩形. 问有多少种多米诺骨牌覆盖. n, m <= 11 . 实现 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #define F(i, a, b) for (register int i = (a); i <= (b); i++) 6 #define LL long long 7 inline

POJ 2411 Mondriaan&#39;s Dream(状态压缩+深搜)

每一行的填充仅与上一行有关系,每行的目的都是至少填充满上一行. 当填充到i行的时候,i-1行某列没填充必须用竖直的方格填充,这是固定的,剩下其余的则搜索填充. 用2进制的01表示不放还是放 第i行只和i-1行有关 枚举i-1行的每个状态,推出由此状态能达到的i行状态 如果i-1行的出发状态某处未放,必然要在i行放一个竖的方块,所以我对上一行状态按位取反之后的状态就是放置了竖方块的状态. 然后用搜索扫一道在i行放横着的方块的所有可能,并且把这些状态累加上i-1的出发状态的方法数,如果该方法数为0,

poj 2288 Islands and Bridges_状态压缩dp_哈密尔顿回路问题

题目链接 题目描写叙述:哈密尔顿路问题.n个点,每个点有权值,设哈密尔顿路为 C1C2...Cn,Ci的权值为Vi,一条哈密尔顿路的值分为三部分计算: 1.每个点的权值之和2.对于图中的每一条CiCi+1,加上Vi*Vi+1 3.对于路径中的连续三个点:CiCi+1Ci+2,若在图中,三点构成三角形,则要加上Vi*Vi+1*Vi+2 求一条汉密尔顿路能够获得的最大值,而且还要输出有多少条这种哈密尔顿路. 这道题的状态感觉不是非常难想,由于依据一般的哈密尔顿路问题,首先想到的是设计二维状态,dp[