BZOJ2574 Store-Keeper

题目

题目地址

思路

仔细分析一下会发现,其实此题的状态数并不多,只有(100*100*4)种,人的移动是不需要的,也就是说,我们只需要知道当箱子在某一个位置时,人能不能从箱子的一个侧面走向另一个侧面。

转化成图论模型也就是说,当一个无向图断掉一个点之后,判断两个点的连通性。

这就让人想到了COCI2006/2007 Final的题,这是那道题的一个子问题。

首先用(Tarjan)(dfs)树建立出来,处理出每个点的(low)值和子树的(dfs)序区间,然后,对于(a),(b),判断断掉(x)之后他们是否联通。

分为3种情况讨论:

  1. 两者都不在x的子树内,那么会发现x断掉对这两点的连通性没有什么影响。
  2. 两者都在x的子树内,那么只需要将他们跳到x的下面那个点,判断该点的low值是否小于dfn[x],然,则说明底下存在一条返祖边回到x的上方,在x断掉之后仍然能够使图联通。
  3. 两者一个在x的子树内一个不在,这种情况与上面类似,仍然讨论是否存在返祖边使图联通即可。

代码

#include<bits/stdc++.h>
#define M 10005
using namespace std;
int n,m,h[M],tt;
char S[105][105];
bool vis[105][105][4];
int dxy[4][2]={1,0,0,1,0,-1,-1,0};
struct edge{int nxt,to;}G[M<<3];
void Add(int a,int b){
    G[++tt]=(edge){h[a],b};
    h[a]=tt;
}
int dfn[M],low[M],tot,R[M],fa[M][15],dep[M];
int ID(int x,int y){return (x-1)*m+y;}
void Tarjan(int x,int f,int d){
    low[x]=dfn[x]=++tot;fa[x][0]=f;dep[x]=d;
    for(int i=1;i<=14;i++)
        fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int i=h[x];i;i=G[i].nxt){
        int u=G[i].to;
        if(u==f)continue;
        if(!dfn[u]){
            Tarjan(u,x,d+1);
            low[x]=min(low[x],low[u]);
        }
        else low[x]=min(low[x],dfn[u]);
    }
    R[x]=tot; 
}
int Up(int x,int step){
    for(int i=14;i>=0;i--)
        if(step&1<<i)x=fa[x][i];
    return x;
}
struct node{
    int x,y,step,fr;
}Q[10005],Q2[40005];
int mark[105][105];int T;
bool check(int x,int y){
    return x>=1&&x<=n&&y>=1&&y<=m&&mark[x][y]!=T&&S[x][y]!='S';   
}
bool bfs(int sx,int sy,int ex,int ey,int cx,int cy){
    int L=0,R=0;
    Q[R++]=(node){sx,sy};mark[sx][sy]=T;
    while(L!=R){
        node e=Q[L++];if(L==10001)L=0;
        if(e.x==ex&&e.y==ey){++T;return 1;}
        for(int i=0;i<4;i++){
            int x=e.x+dxy[i][0];
            int y=e.y+dxy[i][1];
            if(check(x,y)&&!(x==cx&&y==cy)){
                Q[R++]=(node){x,y};
                if(R==10001)R=0;
                mark[x][y]=T;
            }
        }
    }
    ++T;
    return 0;
}
bool In(int a,int b){
    return dfn[a]>=dfn[b]&&dfn[a]<=R[b];
}
bool Ca(int a,int b,int x){
    if(!In(a,x)&&!In(b,x))return 1;
    if(In
原文地址:https://www.cnblogs.com/zryabc/p/11202127.html