Description
Ray又在NPC问题了:这里有一个箱子,还有若干个玩具。
我们可以假设玩具的数量是没有上限的。我们还知道这个箱子是不规则的,或者可以说,他的外形比较像一个矩形,但是内部却有很多突起,这些突起很可恶,他可以一直突到玩具的顶盖部。为了简化这个NPC问题,Ray只保留了一种形状的玩具。
PS:玩具为“十”字形
Ray想知道对于一个给定的箱子,最多可以放下多少个这样的玩具。
Input
第一行两个用空格隔开的整数n 和m表示玩具箱的长度和宽度
第二行到第n+1行,每行m个用空格隔开的字符“#”“.”;“#”表示这里是一个障碍物。“.”表示这里可以放东西。
Output
一行一个整数表示最多的玩具个数
Sample Input
5 4
#.#.
...#
#..#
#...
##.#
Sample Output
2
Hint
0<=n<=100
0<=m<=10
Ray= =天使玩这种辣鸡玩具干什么?(MMM)。
发现这道题和炮兵阵地很像,而且一开始我又陷入了类似炮兵阵地的误区(只开两维,详见炮兵大坑),和炮兵不同的是,迷之突起会相互影响无法兼容,因此我们记下每个凸起位置= =,dp的时候判断一下就可以了。
#include<bits/stdc++.h>
using namespace std;
#define Inc(i,L,r) for(register int i=(L);i<=(r);++i)
int n,m;
int cannot[110];
int cnts,p[30],st[30],num[30];
inline bool ok(int s){
int cnt=0;
for(;s;s>>=1){
if(!(s&1))if(cnt%3!=0)return 0;
if(s&1)++cnt;
}
if(cnt%3)return 0;
return 1;
}
inline void cull(int idx,int s){//我们处理出每个状态,玩具数量和...的中间位置(判凸出)
int cnt=0,tmps=s;
for(int i=1;s;++i,s>>=1){
if(s&1)++cnt;
if(cnt%3==2)p[idx]|=1<<i-1;
}
st[idx]=tmps,num[idx]=cnt/3;
}
int ans,f[110][30][30];
inline void init(){
scanf("%d%d",&n,&m);
Inc(i,0,(1<<m)-1)if(ok(i))cull(++cnts,i);
Inc(i,1,n)Inc(j,1,m){
char c=getchar();while(c!='#'&&c!='.')c=getchar();
cannot[i]+=(c=='#')<<j-1;
}
Inc(i,1,cnts)if(!(st[i]&cannot[2])&&!(p[i]&cannot[1])&&!(p[i]&cannot[3]))
Inc(j,1,cnts)if(!(st[j]&cannot[1])&&!(p[j]&cannot[2])&&!(p[j]&st[i]))f[2][i][j]=num[i];
}
inline void solv(){
Inc(i,3,n-1)Inc(j0,1,cnts)if(!(st[j0]&cannot[i])&&!(p[j0]&cannot[i-1])&&!(p[j0]&cannot[i+1])){
Inc(j1,1,cnts)if(!(st[j1]&cannot[i-1])&&!(p[j1]&cannot[i-2])&&!(p[j1]&cannot[i])){
if(p[j1]&st[j0])continue;
Inc(j2,1,cnts)if(!(st[j2]&cannot[i-2])&&!(p[j2]&cannot[i-3])&&!(p[j1]&cannot[i-1])){
if((p[j2]&st[j1])||(p[j2]&p[j0]))continue;
f[i][j0][j1]=max(f[i][j0][j1],f[i-1][j1][j2]+num[j0]);
}
}
}
Inc(i,2,n-1)Inc(j,1,cnts)Inc(k,1,cnts)ans=max(ans,f[i][j][k]);//在下懒得判了
cout<<ans<<"\n";
}
int main(){
init();
solv();
return 0;
}
/*
6 5
##.##
#...#
##..#
#....
....#
#.###
3
7 7
.......
.......
.......
.......
.......
.......
.......
6
*/