题意:给出一个有向图,问是不是仙人掌图。仙人掌图:每个边只在一个普通环内的强连通图。
解法:tarjan判断强连通分量是否为1个,记录找环的路径,在每找到一个环时遍历路径记录点出现的次数,如果出现有点被记录两次,则说明有边不只在一个环内。
代码:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string> #include<string.h> #include<math.h> #include<limits.h> #include<time.h> #include<stdlib.h> #include<map> #include<queue> #include<set> #include<stack> #include<vector> #define LL long long using namespace std; int n, m; vector <int> edge[20005]; int DFN[20005], Low[20005]; int cnt = 1; int ans = 0; int fa[20005], out[20005]; int flag = 1; void sign(int v, int u) { while(fa[u] != v) { out[u]++; if(out[u] > 1) { flag = 0; return ; } u = fa[u]; } } void tarjan(int v) { DFN[v] = Low[v] = cnt++; int len = edge[v].size(); for(int i = 0; i < len; i++) { int u = edge[v][i]; if(!DFN[u]) { fa[u] = v; tarjan(u); Low[v] = min(Low[v], Low[u]); } else { Low[v] = min(Low[v], DFN[u]); sign(u, v); if(!flag) return ; } } if(DFN[v] == Low[v]) { int tmp; ans++; if(ans > 1) { flag = 0; return ; } } } int main() { int T; scanf("%d", &T); while(T--) { cnt = 1; ans = 0; flag = 1; scanf("%d%d", &n, &m); for(int i = 0; i < n; i++) edge[i].clear(); for(int i = 0; i < m; i++) { int v, u; scanf("%d%d", &v, &u); edge[v].push_back(u); } memset(DFN, 0, sizeof DFN); memset(fa, 0, sizeof fa); memset(out, 0, sizeof out); for(int i = 0; i < n; i++) if(!DFN[i]) tarjan(i); if(flag) printf("YES\n"); else printf("NO\n"); } return 0; }
时间: 2024-10-13 12:43:52