追赶游戏(chase.cpp/in/out) 1S/128M
追赶是两个人在木板上玩的游戏。板子由从1到n编号的格子组成。每对不同的格子,要么相邻,要么不相邻。每位游戏者有一枚棋子。开始时,每个游戏者的棋子放在不同的格子里。每一步,游戏者可以保持他的棋子在原来位置不动,或者移动到一个相邻的格子上。
游戏板有下列特征:
1.它不含三角形,即不存在三个不同的格子满足每两个都是相邻的。
2.每个格子都有可能被每个游戏者走到。
一场游戏是由许多轮组成。一轮中每位游戏者最多能走一步。每轮都是由游戏者A开始。当某一轮时,两个棋子在同一个格子上时,那么我们说游戏者B抓住了游戏者A。
如果两个游戏者都按最优的策略行动,即游戏者A尽可能逃得远,而游戏者B尽可能快地追赶游戏者A,那么对于给定的初始位置,游戏者B最少需要多少轮才能够抓住游戏者A。例如,对于下图的游戏板
相邻的格子(由圆表示)由边相连。如果在游戏开始时,游戏者A和B的棋子各自处于编号为9和4的格子上,那么在第3轮时,游戏者B能抓住游戏者A(如果两个游戏者都按最优策略走)。如果游戏开始时,棋子分别位于编号为8(游戏者A),和编号为4(游戏者B)上,那么游戏者B不能抓住游戏者A(如果A走得正确)
输入格式:
第1行:4个整数n,m,a,b(2≤n≤3000,n-1≤m≤15000,1≤a,b≤n并且a<b),n表示板子上的格子的数量,m表示有多少对相邻格子,a表示游戏者A的棋子所放格子的编号,b表示游戏者B的棋子所放格子的编号。
接下来m行,每行2个整数,表示一对相邻格子的编号。
输出格式:
如果游戏者B不能抓住游戏者A,输出-1,否则输出一个整数,表示游戏者B抓住游戏者A所需要的最少的轮数
样例输入:
9 11 9 4
1 2
3 2
1 4
4 7
7 5
5 1
6 9
8 5
9 8
5 3
4 8
样例输出
3
开始很容易想成博弈,后来发现不是,居然是图论
仔细分析后我们发现,如果A在被B抓住之前到了图中的一个双连通分量里,他就永远不会被抓到,因为即使B挡住了其中一条去路,A仍然可以选择另外一条路走开
那么我们怎么求图中双联通分量呢?很明显应该用到Tajan
用dis[0][i]表示A号点到i号点距离,dis[1][i]表示B号点到i号点距离,不难想到,对于一个双联通分量内的点k,如果有dis[0][k]<dis[1][k],那么输出-1
那么剩下的就是A一定会被追到的情况,这个时候A只能尽量跑远一点,在被B追上之前到达一个让B跑的最远的点,如果这个点为k,则也满足条件
dis[0][k]<dis[1][k]
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int maxn=3005,maxm=30005,inf=0x3f3f3f3f;
inline void _read(int &x){
char t=getchar();bool sign=true;
while(t<'0'||t>'9')
{if(t=='-')sign=false;t=getchar();}
for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';
if(!sign)x=-x;
}
int last[maxn],low[maxn],dfn[maxn],Belong[maxn],cnt[maxn],dis[2][maxn];
int scc,n,m,A,B,vistime;
bool isbri[maxm],vis[maxn],to[maxn];
struct node{
int a,b,Next;
node(int a,int b,int Next):a(a),b(b),Next(Next){}
};
vector<node>s;
void insert(int a,int b){
s.push_back(node(a,b,last[a]));
last[a]=s.size()-1;
s.push_back(node(b,a,last[b]));
last[b]=s.size()-1;
}
void spfa(int op){
int t=(op==B),i;
queue<int>q;
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++)dis[t][i]=inf;
dis[t][op]=0,vis[op]=1;
q.push(op);
while(q.size()){
int x=q.front();q.pop();
vis[x]=0;
for(i=last[x];i>=0;i=s[i].Next){
int v=s[i].b;
if(dis[t][v]>dis[t][x]+1){
dis[t][v]=dis[t][x]+1;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
}
void tajan(int u,int fa){
dfn[u]=low[u]=++vistime;
int i,j,v;
for(i=last[u];i>=0;i=s[i].Next){
int v=s[i].b;
if(dfn[v]==0){
tajan(v,u);
low[u]=min(low[u],low[v]);
if(dfn[u]<low[v])isbri[i]=1,isbri[i^1]=1;
}
else if(v!=fa)low[u]=min(low[u],dfn[v]);
}
}
void dfs(int u){
int i,v;
cnt[scc]++;
Belong[u]=scc;
for(i=last[u];i>=0;i=s[i].Next){
if(isbri[i])continue;
v=s[i].b;
if(Belong[v])continue;
dfs(v);
}
}
int main(){
memset(last,-1,sizeof(last));
int i,j,x,y,ans=0,id,curdis=inf;
_read(n);_read(m);_read(A);_read(B);
for(i=1;i<=m;i++){
_read(x);_read(y);
insert(x,y);
}
tajan(1,0);
for(i=1;i<=n;i++)
if(!Belong[i]){
scc++;
dfs(i);
}
spfa(A);spfa(B);
for(i=1;i<=n;i++)
if(cnt[Belong[i]]>1){
if(dis[0][i]<dis[1][i]){
puts("-1");
return 0;
}
}
else if(dis[0][i]<dis[1][i])ans=max(ans,dis[1][i]);
cout<<ans;
}