codeforces 652E 题解

Pursuit For Artifacts

题目连接:https://codeforc.es/problemset/problem/652/E

题意

  给出一个有向图,问:从A到B是否存在一条路径,路径长度大于0(两点距离只有0和1两个值)

思路

缩点重建图,再dfs
  细节:缩点不提,重新建图关键处理长度为1的边,判断两点是否属于同一个缩点,如果属于则要标记,当A和B路径(包括AB)中包含这个标记缩点时,说明存在一条路径长不为0,其实就是相当于在这个缩点里绕一圈经过那个长为1的边(原图),这时sum也加一;当两点不属于同一个缩点时,建图之间把缩点后的边设为1就行,后面dfs经过这条边时,sum+1,最后到终点时判断sum是否等于0就行。

代码

#include<bits/stdc++.h>
using namespace std;
#define maxn 300005
#define maxm 600005

struct edge
{
	int next, to, len;
} G[maxm];
int head[maxn], num;
void add(int from, int to, int len)
{
	G[++num].next = head[from];
	G[num].to = to;
	G[num].len = len;
	head[from] = num;
}

struct node
{
	int u, v, len;
};

bool instack[maxn];
int low[maxn], dfn[maxn];//时间戳
int sta[maxn], fa[maxn], fuben[maxn];//栈,记录父节点,记录用一个边双连通分量的所有点
int top, id, bcc;//栈顶,时间计数,边双连通分量的个数
int belong[maxn];//判断哪一个点属于哪一个连通分量
void tarjan(int u, int fa)
{
	int i;
	dfn[u] = low[u] = ++id;
	instack[u] = 1;
	sta[++top] = u;
	for (i = head[u]; i != -1; i = G[i].next)
	{
		int v = G[i].to;
		if (v == fa) continue;
		if (!dfn[v])
		{
			tarjan(v, u);
			low[u] = min(low[v], low[u]);
		}
		else if (instack[v])
			low[u] = min(dfn[v], low[u]);
	}

	if (dfn[u] == low[u])
	{
		++bcc;
		do
		{
			i = sta[top--];
			belong[i] = bcc;
			instack[i] = 0;
		} while (i != u);
	}
}
bool flag[maxn];
int st, en;
bool dfs(int to, int fa, int sum)
{
	if (to == en)
	{
		if (sum != 0)
			return true;
		else
			return false;
	}
	for (int i = head[to]; i != -1; i = G[i].next)
	{
		int v = G[i].to;
		if (v != fa)
		{
			if (dfs(v, to, sum + G[i].len + flag[v]))
				return true;
		}
	}
	return false;
}
int main()
{
	vector<node>ff;
	memset(head, -1, sizeof(head));
	int n, m;
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++)
	{
		int x, y, z;
		scanf("%d%d%d", &x, &y, &z);
		ff.push_back(node{ x,y,z });
		add(x, y, z);
		add(y, x, z);
	}

	for (int i = 1; i <= n; i++)
		if (!dfn[i])
			tarjan(i, 0);

	num = 0;
	memset(head, -1, sizeof(head));

	for (int i = 0; i<m; i++)
	{
		int u = ff[i].u, v = ff[i].v, w = ff[i].len;
		if (belong[u] != belong[v])
			add(belong[u], belong[v], w), add(belong[v], belong[u], w);
		else if (w == 1)
			flag[belong[u]] = true;
	}

	scanf("%d%d", &st, &en);
	st = belong[st], en = belong[en];
	if (flag[st] || flag[en])
	{
		printf("YES");
		return 0;
	}
	if (dfs(st, -1, 0))
		printf("YES");
	else
		printf("NO");
	return 0;
}
发布了41 篇原创文章 · 获赞 2 · 访问量 1264

猜你喜欢

转载自blog.csdn.net/qq_41418281/article/details/100018614