BZOJ4256 推箱子

来源:互联网 发布:淘宝我的空间怎么设置 编辑:程序博客网 时间:2024/05/29 02:39

首先将空地与空地之间连边,转化为一个无向图。


令dp[i][j][0/1/2/3]表示箱子在(i,j),人在箱子旁4个方向中的一个时是否存在方案(和NOIP2013华容道类似)

则有2种转移:dp[i][j][k]->dp[i][j][l](从方向k可以不通过(i,j)到方向l)

   dp[i][j][k]->dp[i'][j'][k](人推动箱子)

最后答案就是枚举所有的(i,j),计算人的合法位置个数。


现在问题的关键就是判联通和计算人的合法位置个数。

这可以用tarjan实现。


时间复杂度O(nm)

#include<bits/stdc++.h>#define maxn 1010#define maxm 1001000#define id(x,y) (((x)-1)*(m)+(y))using namespace std;struct edge{int r,nxt;}e[maxm<<3];struct data{int x,y,v;}q[maxm*4];int head[maxm],esz,sz,low[maxm],l,r;int rig[maxm],tim,dfn[maxm],sx,sy,n,m,f[maxn][maxn][4],fa[maxm];char s[maxn][maxn];int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};void inline addedge(int u,int v){e[++esz].r=v;e[esz].nxt=head[u];head[u]=esz;e[++esz].r=u;e[esz].nxt=head[v];head[v]=esz;}int inline chkin(int x,int y){return x>=1&&y>=1&&x<=n&&y<=m;}void inline tarjan(int u){low[u]=dfn[u]=++tim;for(int t=head[u];t;t=e[t].nxt)if(e[t].r!=fa[u])if(!dfn[e[t].r]){fa[e[t].r]=u,tarjan(e[t].r);low[u]=min(low[u],low[e[t].r]);} else low[u]=min(low[u],dfn[e[t].r]);rig[u]=tim;}int get(int u,int v){for(int t=head[u];t;t=e[t].nxt)if(dfn[e[t].r]>dfn[u]&&dfn[e[t].r]<=dfn[v]&&dfn[v]<=rig[e[t].r])return e[t].r;return 0;}bool cango(int x,int u,int v){if(!dfn[u]||!dfn[v]||!dfn[x])return false;int a=get(x,u),b=get(x,v);if(a==b||(!a&&!b))return true;if(!a&&low[b]<dfn[x])return true;if(!b&&low[a]<dfn[x])return true;if(low[b]<dfn[x]&&low[a]<dfn[x])return true;return false;}bool isgood(int x,int y,int k){int nx=x+dx[k],ny=y+dy[k];if(!chkin(nx,ny)||s[nx][ny]=='#')return false;return true;}int size(int u){return rig[u]-dfn[u]+1;}int main(){//freopen("A.in","r",stdin);scanf("%d%d",&n,&m);for(int i=1;i<=n;++i)scanf("%s",s[i]+1);for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)if(s[i][j]!='#')for(int k=0;k<4;++k){int ni=i+dx[k],nj=j+dy[k];if(!chkin(ni,nj)||s[ni][nj]=='#')continue;if(id(i,j)<id(ni,nj))addedge(id(i,j),id(ni,nj));}for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)if(s[i][j]=='X')sx=i,sy=j;tarjan(id(sx,sy)),sz=tim;for(int i=0;i<4;++i)if(isgood(sx,sy,i))q[r++]=data{sx,sy,i},f[sx][sy][i]=1;while(l<r){data d=q[l++];int x=d.x,y=d.y,v=d.v;if(isgood(x+dx[v],y+dy[v],v)){int nx=x+dx[v],ny=y+dy[v];if(!f[nx][ny][v])f[nx][ny][v]=1,q[r++]=data{nx,ny,v};}for(int i=0;i<4;++i)if(!f[x][y][i]&&isgood(x,y,i)&&cango(id(x,y),id(x+dx[v],y+dy[v]),id(x+dx[i],y+dy[i])))f[x][y][i]=1,q[r++]=data{x,y,i};}long long ans=0;int z=id(sx,sy);for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)if(s[i][j]=='.'){int v[6]={0};int nans=ans;for(int k=0;k<4;++k)if(f[i][j][k])for(int l=0;l<4;++l)if(cango(id(i,j),id(i+dx[k],j+dy[k]),id(i+dx[l],j+dy[l])))v[l]=1;for(int k=0;k<4;++k)if(v[k]&&isgood(i,j,k)){int x=id(i+dx[k],j+dy[k]);if(!dfn[x])continue;if(fa[x]==id(i,j)){ans+=size(x);if(dfn[x]<=dfn[z]&&dfn[z]<=rig[x])ans--;}if(low[x]<dfn[id(i,j)])v[4]=1;}if(v[4]){int x=id(i,j);ans+=sz-size(x);if(dfn[z]<dfn[x]||rig[x]<dfn[z])ans--;}}printf("%lld",ans);}