当前位置: 代码迷 >> 综合 >> 强连通分量+缩点 codeforces652E Pursuit For Artifacts
  详细解决方案

强连通分量+缩点 codeforces652E Pursuit For Artifacts

热度:8   发布时间:2023-12-14 03:17:35.0

传送门:点击打开链接

题意:告诉你一个带权边无向图,边的权值只有0和1,告诉你起点和终点,问是否能使得从起点出发到终点时,路径边权和不等于0,每边最多只允许通过一次。

思路:因为"边不能走重复的",往往不能走重复边都可以和强连通分量结合起来。

这题我们首先求无向图所有的强连通分量并缩点,对于每一个强连通分量,如果里面有一条边的权值为1,那么最后缩成的点我们也给一个权值1。

缩点全部完成后,就会形成一颗树,树上点带权值,边也带权值。

那么我只要看st缩点后的节点u,和ed缩点后的节点v,在树中的路径中,是否有边权等于1,或者是点权等于1,只要出现了,那么题目都是输出YES

至于边权等于1就输出YES很好理解,不多说太多,主要理解下点权为什么等于1,也是输出YES

某一条边走过以后,就不能走第二遍了,相当于把这条边删掉。

根据强连通分量的性质,删了这条边后,两个点还是连通的。

所以就有了一条性质,在同一个强连通分量中,假如有两个节点u和v,和一条有效边s,我一定能从u,通过一条路径走到v,并且经过s

这就是缩点后还能搞的原理了。

变成树后,直接一个DFS从起点搜一下到终点,就ok了

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <string>
#include <vector>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;const int MX = 3e5 + 5;int Head[MX], erear;
struct Edge {int u, v, nxt, z;
} E[MX << 1];
void edge_init() {erear = 0;memset(Head, -1, sizeof(Head));
}
void edge_add(int u, int v, int z) {E[erear].u = u;E[erear].v = v;E[erear].z = z;E[erear].nxt = Head[u];Head[u] = erear++;
}int n, m;
int DFN[MX], Low[MX], dsz;
int Stack[MX], inStack[MX], Belong[MX], bsz, ssz;
int A[MX];void trajan(int u, int e) {inStack[u] = 1;Stack[++ssz] = u;DFN[u] = Low[u] = ++dsz;for(int i = Head[u]; ~i; i = E[i].nxt) {int v = E[i].v;if((i ^ 1) == e) continue;if(!DFN[v]) {trajan(v, i);Low[u] = min(Low[u], Low[v]);} else if(inStack[v]) {Low[u] = min(Low[u], Low[v]);}}if(DFN[u] == Low[u]) {bsz++; int v;do {v = Stack[ssz--];inStack[v] = 0;Belong[v] = bsz;} while(ssz && v != u);}
}
void tarjan_solve(int n) {dsz = bsz = ssz = 0;memset(DFN, 0, sizeof(DFN));for(int i = 1; i <= n; i++) {if(!DFN[i]) trajan(i, -1);}
}
bool DFS(int st, int ed, int f, int s) {s |= A[st];if(st == ed) return s;for(int i = Head[st]; ~i; i = E[i].nxt) {int v = E[i].v;if(v == f) continue;if(DFS(v, ed, st, s | E[i].z)) return true;}return false;
}int main() {edge_init(); //FIN;scanf("%d%d", &n, &m);for(int i = 1; i <= m; i++) {int u, v, z;scanf("%d%d%d", &u, &v, &z);edge_add(u, v, z);edge_add(v, u, z);}tarjan_solve(n);int etot = erear;edge_init();for(int i = 0; i < etot; i ++) {int u = Belong[E[i].u], v = Belong[E[i].v];if(u == v) A[u] |= E[i].z;else edge_add(u, v, E[i].z);}int st, ed;scanf("%d%d", &st, &ed);if(DFS(Belong[st], Belong[ed], -1, 0)) {printf("YES\n");} else printf("NO\n");return 0;
}