传送门:点击打开链接
题意:告诉你一个带权边无向图,边的权值只有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; }