题意:
众所周知,GFW的出现促进了社会的和谐。Wayne于是想研究一下GFW。
Wayne喜欢网格,所以他把一些网站排成了N_ M的网格,每个格子代表一个网站。每个网站有一个评分,当然评分可正可负。现在Wayne想用一堵“墙”围住一些网站,使得评分和最大。所谓“墙”,就是一个由网格的边组成的简单多边形,不能自交,也不能有空洞。
过了一会儿Wayne发现这个模型太一般了。出于一些原因,有些网站必须在“墙”外,我们称之为“坏网站”;而有些网站必须在“墙”内,我们称之为“好网站”。当然了,“坏网站”的评分不一定低,“好网站”的评分不一定高。Wayne又想知道,这种情况下,能够得到的最大评分和。注意,并不总是存在合法的方案,所以当无法实现时,输出“Can not establish GFW.”。
题解:
挺好的插头dp。
首先是状态的设计,规定回路中的格子是选中的,除了最下方的和最右方的。
如图:
红色格子是在当前回路下选择的区域。
考虑怎么判断一个格子是否被圈住了,用射线法, 每个格子向左做一条射线,假如经过奇数条边线,那么就在圈内,否则在圈外。
转移的时候判断一下当前格子左边有多少下插头就可以了。
code:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
const int mod=100037,inf=1<<30;
int list[2][mod],state[2][mod],hash[mod],num[2],now,ans=-inf;
int map[15][15],n,m,val[15][15];
int get(int s,int p) {return (s>>((p-1)*2))&3;}
bool C[15][15];
void change(int &s,int p,int c) {s^=get(s,p)<<((p-1)*2);s^=c<<((p-1)*2);}
void update(int &x,int y) {x=x>y?x:y;}
void add(int st,int sum)
{
int s=st%mod;
while(hash[s]&&list[now][hash[s]]!=st) (s+=1)%=mod;
if(!hash[s]) hash[s]=++num[now],list[now][num[now]]=st,state[now][num[now]]=sum;
else update(state[now][hash[s]],sum);
}
bool check(int st)
{
int tot=0;
for(int i=1;i<=m+1;i++) if(get(st,i)) tot++;
return tot==2;
}
void ins(int x,int y,int st,int sum)
{
int tot=0;for(int i=1;i<=y;i++) tot+=(get(st,i)!=0);
if((tot&1)&&map[x][y]!=1) add(st,sum+val[x][y]);
if(!(tot&1)&&map[x][y]!=2) add(st,sum);
}
void solve()
{
state[0][1]=list[0][1]=now=0;num[0]=1;ans=-inf;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
now^=1;num[now]=0;memset(hash,0,sizeof(hash));
for(int k=1;k<=num[!now];k++)
{
int st=list[!now][k],p=get(st,j),q=get(st,j+1),sum=state[!now][k];
if(!p&&!q)
{
ins(i,j,st,sum);
if(i+1<=n&&j+1<=m) change(st,j,1),change(st,j+1,2),ins(i,j,st,sum);
}
else if(!p&&q)
{
if(j+1<=m) ins(i,j,st,sum);
if(i+1<=n) change(st,j,q),change(st,j+1,0),ins(i,j,st,sum);
}
else if(p&&!q)
{
if(i+1<=n) ins(i,j,st,sum);
if(j+1<=m) change(st,j,0),change(st,j+1,p),ins(i,j,st,sum);
}
else if(p==1&&q==2) {if(check(st)&&C[i][j]) update(ans,sum);}
else if(p==2&&q==1) {change(st,j,0);change(st,j+1,0);ins(i,j,st,sum);}
else if(p==1&&q==1)
{
int top=1;
for(int pos=j+2;pos<=m+1;pos++)
{
int tmp=get(st,pos);
if(tmp==1) top++;if(tmp==2) top--;
if(!top) {change(st,j,0);change(st,j+1,0);change(st,pos,1);ins(i,j,st,sum);break;}
}
}
else if(p==2&&q==2)
{
int top=1;
for(int pos=j-1;pos;pos--)
{
int tmp=get(st,pos);
if(tmp==2) top++;if(tmp==1) top--;
if(!top) {change(st,j,0);change(st,j+1,0);change(st,pos,2);ins(i,j,st,sum);break;}
}
}
}
}
for(int j=1;j<=num[now];j++) list[now][j]<<=2;
}
}
int main()
{
scanf("%d %d",&n,&m);n++;m++;
for(int i=1;i<n;i++)
for(int j=1;j<m;j++) scanf("%d",&val[i][j]);
memset(C,true,sizeof(C));
solve();
if(ans==-inf) printf("Can not establish GFW.\n");
else printf("%d\n",ans);
for(int i=1;i<n;i++)
for(int j=1;j<m;j++) scanf("%d",&map[i][j]);
memset(C,false,sizeof(C));bool flag=false;
for(int i=n;i>=1;i--)
{
if(flag) break;
for(int j=m;j>=1;j--)
{
if(map[i][j]==2) {flag=true;break;}
C[i][j]=true;
}
}
solve();
if(ans==-inf) printf("Can not establish GFW.\n");
else printf("%d\n",ans);
}