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

 

Bugs Integrated, Inc.
Time Limit: 15000MS   Memory Limit: 30000K
Total Submissions: 5762   Accepted: 2069
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.
1038 Bugs Integrated, Inc.//状态压缩DP_第1张图片
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
相当感谢这个博客 http://hi.baidu.com/chinaeli/blog/item/b932d4b430d60ac636d3ca34.html

 

#include<cstdio>//0(nm3^m) #include<cstring> int n,m,k,count; int plate[151][11];//记录棋盘 int num[2][59050];//滚动数组,只用记录这两行 //M位的三进制共有3^M种状态,( 0<M<=10),因此最大有59049种状态,采用滚动数组,只要开一个2*59049大小的二维数组就可以了 int p[11],q[11]; int mark[59050][11]; int rmax; int getnum(int *p)//从3进制数获得状态数。存储对应状态 { int sum=0; for(int i=1;i<=m;i++) sum=sum*3+p[i]; return sum; } void cal(int count) { for(int i=0;i<count;i++)//从状态数分解成3进制数。进行状态转移 { int state=i; int num=m; while(state) { mark[i][num--]=state%3; state/=3; } for(; num>=1; num--) //前面不够的位用0补位 mark[i][num]=0; } } void search(int step,int k,int nownum,int qnum)//深搜,搜step+1层,往下搜一层 { if(nownum>num[(step+1)%2][qnum]) //如果上一个状态的最大数大于这个状态的最大数,更新。 num[(step+1)%2][qnum]=nownum;//注意是以上面一行的Q的状态为第二个坐标 if(nownum>rmax) rmax=nownum;//如果上一个状态的最大数大于全局最大数,更新。 for(int j=k;j<m;j++)//从开始搜索的位置到最后一位 { if(q[j]==0&&q[j+1]==0&&p[j]==0&&p[j+1]==0)//可以放置3*2的芯片 { q[j]=q[j+1]=2; search(step,j+2,nownum+1,getnum(q));//按此情况深搜 q[j]=q[j+1]=0;//回复原态 } if(j+2<=m) { if(p[j]<=1&&p[j+1]<=1&&p[j+2]<=1&&q[j]==0&&q[j+1]==0&&q[j+2]==0)//放置2*3芯片 { q[j]=q[j+1]=q[j+2]=2; search(step,j+3,nownum+1,getnum(q));//深搜 q[j]=q[j+1]=q[j+2]=0;//回复原态 } } } } int main() { int cas; scanf("%d",&cas); while(cas--) { rmax=0; scanf("%d%d%d",&n,&m,&k); memset(plate,0,sizeof(plate)); memset(num,-1,sizeof(num));//将边界条件=0,其余初始为-1,表示该状态不可到达或者尚未到达 for(int i=1;i<=k;i++) { int x,y; scanf("%d%d",&x,&y); plate[x][y]=1;//打上标记 } count=1; for(int i=1;i<=m;i++) { count*=3; p[i]=plate[1][i]+1;//必须从这种状态开始,只有这种状态能够从最开就到达 //因为没有上一行,所以首先必须全是第一类,后来如果第一行该位置仍然不能插入,那就变为第二类 } cal(count); num[1][getnum(p)]=0;//初始状态 for(int i=1;i<n;i++) { memset(num[(i+1)%2],-1,sizeof(num[(i+1)%2])); for(int j=0;j<count;j++) { if(num[i%2][j]==-1) continue;//为-1说明上面那个状态就一直没有到达过,至少要为0 for(int k=1;k<=m;k++) p[k]=mark[j][k]; for(int k=1;k<=m;k++)//状态从上两行推到了下两行 { q[k]=p[k]==0?p[k]:p[k]-1;//某两行的状态与下移一行的状态(如p表示1,2行的状态,q表示2,3行的状态) //转移方程 q=(1)p>0,p-1(2)p=0,0 if(plate[i+1][k]==1) q[k]=2; } search(i,1,num[i%2][j],getnum(q));//得到上两行的状态 } } printf("%d/n",rmax); } return 0; } 

你可能感兴趣的:(Integer,search,input,each,output,bugs)