题目链接:
P3520 [POI2011] SMI-Garbage - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
很明显的欧拉回路模板题,对于一个图,若目的地与终点相同则不做处理,若目的地与终点的状态不同则加入该边,走一遍欧拉回路即可:
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int N = 100010, M = 2000010; int sum; int n, m; int d[N]; bool st[M]; int ans[M], cnt; int h[N], e[M], ne[M], idx; void add(int a, int b)//邻接表模板 { e[idx] = b; ne[idx] = h[a]; h[a] = idx; idx ++ ; } void dfs(int u, int root) { d[u] -= 2;//u走进和走出度减少2 ans[++ cnt ] = u;//走过u这个点将它读入答案中 for (int i = h[u]; i != -1; i = ne[i]) { int j = e[i]; h[u] = i; if (st[i]) continue;//若走过这条边,这忽略 st[i] = st[i ^ 1] = true;//将边i与i的方向边置为走过 if (j == root)//若找到了一个环 { sum ++ ;//环总数 ++ ; ans[++ cnt] = j;//将j记录为答案 return ;//直接结束该循环 } dfs(j, root); return ;//一次只能选择一条路走,所以递归走了一条边时, //这个点的其他边就不能走 } } int main() { cin >> n >> m; memset(h, -1, sizeof h); for (int i = 1; i <= m; i ++ ) { int a, b, s, t; scanf("%d %d %d %d", &a, &b, &s, &t); if (s ^ t)//若状态与终点不同 { add(a, b); add(b, a); d[a] ++ , d[b] ++ ; } } for (int i = 1; i <= n; i ++ ) if (d[i] & 1)//存在一个度为0说明肯定存在一些点他不在环里面 { puts("NIE"); return 0; } for (int i = 1; i <= n; i ++ ) { if (!d[i]) continue; while (d[i]) dfs(i, i);//只要该点度不为0就一直找 } printf("%d\n", sum); for (int i = 1; i <= cnt; i ++ )//找出循环的数组,输出大难 { int root = ans[i]; int j = i + 1; while (ans[j] != root && j <= cnt) j ++ ; //从i到j即为一个环 printf("%d ", j - i);//输出环中点的数量 for (int k = i; k <= j; k ++ ) printf("%d ", ans[k]); i = j; puts(""); } return 0; }