[博弈 图论] BZOJ 2922 [Poi1998]Chase

%%%BYVOID 


注意到题上的一个看似无关紧要的条件,“不包括三角形”,这是一个突破口。由这个条件,我们可以证明,如果一个图不存在度数为1的顶点,B永远也追不上A。也就是B想追上A,必须让A“走投无路”。

于是我们首先把原图处理一下,求出对于A来说的安全区。对于A来说的安全区,也就是一个没有度为1的顶点的最大子图。我们把这个安全区求出,并标记上。

A要想不被B抓住,则一定要向安全区中逃跑。如果A能够在B追上A之前逃离到安全区,则B就永远也追不上A。否则,A无论如何也会被B追上。在A“必死无疑”的时候,A要想尽可能晚的被B追上,就必须想远离B的方向跑。

有了以上的分析,得出下列算法 1、求出安全区的顶点。 2、分别求出A,B初始位置开始,到每个顶点的距离,记作DA[i]和DB[i]。 3、若存在安全区中的顶点k,使得DA[k]<DB[k],则B追不上A,输出"NIE",结束。 4、如果不存在上述顶点k,则找到满足DA[i]<DB[i]时,DB[i]的最大值,输出DB[i]的最大值。


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef pair<int,int> abcd;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}

inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=3005;
const int M=15005;

struct edge{  
  int u,v,next;  
}G[M<<1];

int head[N],inum=1;  
  
inline void add(int u,int v,int p){  
  G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;  
}

int n,m,A,B;
abcd edges[M];

int Q[N],l,r;

int DA[N],DB[N];
int dan[N];

#define V G[p].v

inline void Dist(){
  memset(DA,-1,sizeof(DA));
  l=r=-1;
  Q[++r]=A; DA[A]=0;
  while (l<r){
    int u=Q[++l];
    for (int p=head[u];p;p=G[p].next)
      if (DA[V]==-1)
	DA[V]=DA[u]+1,Q[++r]=V;
  }
  memset(DB,-1,sizeof(DB));
  l=r=-1;
  Q[++r]=B; DB[B]=0;
  while (l<r){
    int u=Q[++l];
    for (int p=head[u];p;p=G[p].next)
      if (DB[V]==-1)
	DB[V]=DB[u]+1,Q[++r]=V;
  }
}

int deg[N];

inline void Safe(){
  l=r=-1;
  for (int i=1;i<=n;i++) if (deg[i]==1) Q[++r]=i;
  while (l<r){
    int u=Q[++l];
    dan[u]=1;
    for (int p=head[u];p;p=G[p].next){
      deg[V]--;
      if (deg[V]==1) Q[++r]=V;
    }
  }
}

int main(){
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); read(m); read(A); read(B);
  for (int i=1;i<=m;i++) read(edges[i].first),read(edges[i].second);
  sort(edges+1,edges+m+1);
  m=unique(edges+1,edges+m+1)-edges-1;
  for (int i=1;i<=m;i++){
    add(edges[i].first,edges[i].second,++inum),add(edges[i].second,edges[i].first,++inum);
    deg[edges[i].first]++; deg[edges[i].second]++;
  }
  Dist();
  Safe();
  int Ans=0;
  for (int i=1;i<=n;i++){
    if (!dan[i] && DA[i]<DB[i])
      return printf("NIE\n"),0;
    if (DA[i]<DB[i])
      Ans=max(Ans,DB[i]);
  }
  printf("%d\n",Ans);
  return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值