题解 P7370 【[COCI2018-2019#4] Wand】

想了解背景的同学可以去P7369

分析

利用初中的数形结合思想,因为魔杖只有可能从失败的女巫传给胜利的女巫,所以她们之间的关系就可以用一条有向边来表示,如 2 1 可以转化为 1->2,表示 1122 有一条有向边,即魔杖可从 11 传到 22

这样问题就清晰可见了。如果编号为 xx 的女巫最后拿到魔杖,那么 11 号女巫手中的魔杖一定直接或间接传给她,即一定有一条从 11 号女巫到 xx 号女巫的路线。而对于其他的战斗,因为可以随意调整顺序,我们只要把失败者不是 11 号女巫全部调到前面,把失败者是 11 号女巫全部调到最后,就不会影响最后的结果,换句话说,其他的战斗对这条路径没有任何影响

我们用邻接表存储每条有向边,建立一个 bool b[N] 数组存储每个点是否被走过,然后从 11 号节点开始,不断沿着他的每条边到达下一个未被标记的点,将那个点标记,并继续搜索下去,直到无点可走注意开始时不要标记 11 号节点,因为她是把魔杖传出去的,只有之后传回她时才能标记。而能走到的每个点就能说明她们和 11 号节点存在一条路径,即她们是能最后拿到魔杖的女巫。

坑点

除了上面说的开始时不能标记 11 号节点外,还要在全部搜索完后特判一次 11 号节点,因为有一种可能情况: 11 号女巫从来没有失败过,即 11 号节点的出度为零,这时最后魔杖只在 11 号女巫手中,而我们之前的搜索中没有标记,这样就会 WA 一个点(我卡了好久QWQ),所以要特判一下 if(!a[1].size())b[1]=1;,其中 a1a_1 数组表示击败 11 号女巫的人,即从 11 号节点出发的有向边,而 a1.size()a_1.size() 表示她失败的次数,即出度

代码

#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;
}
posted @ 2021-02-20 09:40  luckydrawbox  阅读(13)  评论(0)    收藏  举报  来源