CF29E Quarrel 题解
我们可以另 \(f_{u,v,t}\) 为 A 在 \(u\),B 在 \(v\) ,并且当前轮到第 \(t\) 个人(\(0\) 代表 A,\(1\) 代表 B)移动是的最小步数。
那么就可以使用 BFS 来挨个进行松弛,松弛的时候记录前驱。
注意:在移动 B 的时候,要注意 B 的目的地不能是 A 当前在的位置。
核心代码:
int f[505][505][2],vis[505][505][2],pre[505][505][2][2];
struct node
{
int u;
int v;
int p;
};
int head[505],to[20005],nxt[20005],tot=0;
void add(int u,int v)
{
nxt[++tot]=head[u];
head[u]=tot;
to[tot]=v;
}
void bfs(int n)
{
queue<node> q;
memset(f,63,sizeof f);
q.push((node){1,n,0});f[1][n][0]=0;
while(!q.empty())
{
int u=q.front().u,v=q.front().v,p=q.front().p;q.pop();
vis[u][v][p]=0;
if(!p)
{
for(register int i=head[u];i;i=nxt[i])
{
//这里不用判断是否相等,因为此时只有A走了,B还没走
if(f[to[i]][v][1]>f[u][v][0]+1)//松弛
{
f[to[i]][v][1]=f[u][v][0]+1;
pre[to[i]][v][1][0]=u;
pre[to[i]][v][1][1]=v;
//记录前驱
if(!vis[to[i]][v][1])
{
q.push((node){to[i],v,1});
vis[to[i]][v][1]=1;
}
}
}
}
else
{
for(register int i=head[v];i;i=nxt[i])
{
if(to[i]==u)continue;
if(f[u][to[i]][0]>f[u][v][1])
{
f[u][to[i]][0]=f[u][v][1];
pre[u][to[i]][0][0]=u;
pre[u][to[i]][0][1]=v;
if(!vis[u][to[i]][0])
{
q.push((node){u,to[i],0});
vis[u][to[i]][0]=1;
}
}
}
}
}
}
我好菜啊。——ฅ(OωO)ฅ