题解 P7370 【[COCI2018-2019#4] Wand】
想了解背景的同学可以去P7369
分析
利用初中的数形结合思想,因为魔杖只有可能从失败的女巫传给胜利的女巫,所以她们之间的关系就可以用一条有向边来表示,如 2 1 可以转化为 1->2,表示 到 有一条有向边,即魔杖可从 传到 。
这样问题就清晰可见了。如果编号为 的女巫最后拿到魔杖,那么 号女巫手中的魔杖一定直接或间接传给她,即一定有一条从 号女巫到 号女巫的路线。而对于其他的战斗,因为可以随意调整顺序,我们只要把失败者不是 号女巫全部调到前面,把失败者是 号女巫全部调到最后,就不会影响最后的结果,换句话说,其他的战斗对这条路径没有任何影响。
我们用邻接表来存储每条有向边,建立一个 bool b[N] 数组存储每个点是否被走过,然后从 号节点开始,不断沿着他的每条边到达下一个未被标记的点,将那个点标记,并继续搜索下去,直到无点可走,注意开始时不要标记 号节点,因为她是把魔杖传出去的,只有之后传回她时才能标记。而能走到的每个点就能说明她们和 号节点存在一条路径,即她们是能最后拿到魔杖的女巫。
坑点
除了上面说的开始时不能标记 号节点外,还要在全部搜索完后特判一次 号节点,因为有一种可能情况: 号女巫从来没有失败过,即 号节点的出度为零,这时最后魔杖只在 号女巫手中,而我们之前的搜索中没有标记,这样就会 WA 一个点(我卡了好久QWQ),所以要特判一下 if(!a[1].size())b[1]=1;,其中 数组表示击败 号女巫的人,即从 号节点出发的有向边,而 表示她失败的次数,即出度。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,x,y;
bool b[N];//每个点是否走过
vector<int>a[N];//邻接表存储有向边
void dfs(int x)//搜索
{
int l=a[x].size();
for(int i=0;i<l;i++)//遍历每个能走到的点
{
if(!b[a[x][i]])//如果没走过就标记并继续搜索
{
b[a[x][i]]=1;
dfs(a[x][i]);
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>x>>y;
a[y].push_back(x);//添加有向边
}
dfs(1);//1号节点不标记
if(!a[1].size())b[1]=1;//特判别忘了
for(int i=1;i<=n;i++)
{
cout<<b[i];//能走到的点就有可能最后拿到魔杖
}
return 0;
}

浙公网安备 33010602011771号