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;
}