数据范围 1<=n<=150,1<=m<=10
m很小,可以考虑状压。
为方便把01互换,找全1矩阵。
2*3的海豹,除了横着贴也可竖着贴,这一行选择只受前两行影响,f[i][j][k]表示海豹数,j是i-1行状态,即j二进制这一位是1表示该点可用且之前没有用,k是i-2行状态。枚举j,k,j是a[i-1]子集,枚举s子集黑科技
for(int j=s;j;j=(j-1)&s);
上2行状态确定后,暴力枚举选海豹,更新答案,这样做比较暴力,需卡常,f要滚动,不用memset,因为同一f[0/1]至少差两行,不会相互影响,且i变大,f不会变小,f[k][a][b] > num,没有必要更新其子集。
#prag\
ma GCC optimize("Ofast")
#include <cstdio>
#include <cstring>
inline void read(int &x) {
char c; while((c=getchar())<'0'||c>'9');
x=c-'0';while((c=getchar())>='0'&&c<='9') x=x*10+c-'0';
}
#define R register
int f[2][1025][1025],ans;
__attribute__((optimize("-Os"))) inline void dfs(R int a,R int b,R int c,R int num,R int k,R int li) {
if (f[k][a][b] > num) return;
if (ans < num) ans = num;
f[k][a][b] = num;
R int t = a&b&c;
t = t&(t>>1)&li;
while (t) {
R int tp = t&-t;
t ^= tp;
R int p = tp|(tp<<1);
dfs(a^p,b^p,c^p,num+1,k,~(tp-1));
}
t = a&b&li;
t = t&(t>>1)&(t>>2);
while (t) {
R int tp = t&-t;
t ^= tp;
R int p = tp|(tp<<1)|(tp<<2);
dfs(a^p,b^p,c,num+1,k,~(tp-1));
}
}
__attribute__((optimize("-Os"))) inline int work() {
R int a[152],n,m; memset(a,0,sizeof a);
read(n); read(m);
for (R int i = 1; i <= n; i++)
for (R int j = 0,x; j < m; j++)
read(x),a[i] |= (x^1)<<j;
for (R int i = 2; i <= n; i++) {
for (R int j = a[i-1]; ; j = (j-1)&a[i-1]) {
for (R int k = a[i-2]; ; k = (k-1)&a[i-2]) {
dfs(a[i],j,k,f[(i&1)^1][j][k],i&1,(1<<11)-1);
if (!k) break;
}
if(!j) break;
}
}
printf("%d",ans);
return 0;
}
int haha = work();
main() {;}
题目描述 Description
HR突然想给家里的墙上贴海豹(误)。
HR家有一面很大很大的墙(HR平时就对着这面墙想ZX)。但是当他生气的时候就会对着这面墙撞啊撞,导致墙上出现了很多窟窿,窟窿上不能贴海豹。这面墙是nm大小的,他想贴很多23的海豹,当然除了横着贴也可竖着贴。
他想让你告诉他,他可以在这面墙上最多可以贴多少海豹。
输入描述 Input Description
输入文件第一行是2个整数 n、m,表示墙大小为n*m。
接下来的n行,每行有m个整数0或1,1表示该位置已经被HR撞出窟窿了,0表示空白。
输出描述 Output Description
最多能贴多少海豹。