题目大意:你有一个大小为 的矩形,其中有一些格子是不能选择的,现在问最多能从中完整的取出几个 (可旋转)的矩形。
思路:看到
相差如此之大,很容易让人浮想联翩。所以想到状压。
但是考虑状态。
的片片,在竖着摆放的时候,我们肯定需要知道他上面两行的状态,所以行被占用的情况就采用三进制状压(据说四进制状压会比较好写但是浪费空间)。
定义状态:
表示前
行,第
行的状态是
下最多能取出几个矩形。
其中
的每一位分别有如下含义
- 0:上一行和上上一行都是空的。
- 1:上一行是空的,上上行被占用。
- 2:上一行被占用(上上行不管,因为上一行被占用,无论当前怎么摆放都与上上行无关)。
考虑转移,枚举行和上一行的状态,通过DFS,枚举这里横着还是竖着放这还是不放这个块即可。
滚动数组,不然MLE。记得清空数组。
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<cctype>
#define pa pair<int,int>
#define INF 0x3f3f3f3f
#define inf 0x3f
#define fi first
#define se second
#define mp make_pair
#define ll long long
#define ull unsigned long long
#define pb push_back
using namespace std;
inline ll read()
{
long long f=1,sum=0;
char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-1;c=getchar();}
while (isdigit(c)) {sum=sum*10+c-'0';c=getchar();}
return sum*f;
}
#define MAXN 160
#define MAXM 100010
int f[2][MAXM],a[MAXN][MAXN],P[MAXN],n,m;
int S[2][15];
int getS(int tmp[])
{
int ans=0;
for (int i=0;i<m;i++)
ans+=tmp[i]*P[i];
return ans;
}
void backS(int S,int tmp[])
{
for (int i=0;i<m;i++)
tmp[i]=S%3,S/=3;
}
int now,last;
void dfs(int i,int num,int St)
{
if (i>=m) return ;
if (i+2<m && !S[1][i] && !S[1][i+1] && !S[1][i+2])
{
S[1][i+1]=S[1][i]=S[1][i+2]=2;
int s=getS(S[1]);
f[now][s]=max(f[now][s],num+1);
dfs(i+3,num+1,s);
S[1][i]=S[1][i+1]=S[1][i+2]=0;
}
if (i+1<m && !S[1][i] && !S[1][i+1] && !S[0][i] && !S[0][i+1])
{
S[1][i]=S[1][i+1]=2;
int s=getS(S[1]);
f[now][s]=max(f[now][s],num+1);
dfs(i+2,num+1,s);
S[1][i]=S[1][i+1]=0;
}
f[now][St]=max(f[now][St],f[last][getS(S[0])]);
dfs(i+1,num,St);
}
int main()
{
int T;
scanf("%d",&T);
P[0]=1;
for (int i=1;i<=14;i++)
P[i]=P[i-1]*3;
while (T--)
{
memset(a,0,sizeof(a));
int num;
scanf("%d%d%d",&n,&m,&num);
for (int i=1;i<=num;i++)
{
int x,y;
scanf("%d%d",&x,&y);
a[--x][--y]=1;
}
memset(f,-1,sizeof(f));
for (int i=0;i<m;i++)
S[1][i]=a[0][i]?2:1;
f[0][getS(S[1])]=0;
last=1,now=0;
for (int i=1;i<n;i++)
{
last^=1,now^=1;
memset(f[now],-1,sizeof(f[now]));
for (int state=0;state<P[m];state++)
{
if (f[last][state]==-1) continue;
backS(state,S[0]);
for (int j=0;j<m;j++)
S[1][j]=a[i][j]?2:(!S[0][j]?0:S[0][j]-1);
dfs(0,f[last][state],getS(S[1]));
}
}
int ans=0;
for (int i=0;i<P[m];i++)
ans=max(ans,f[now][i]);
cout<<ans<<endl;
}
return 0;
}