题解 [POI2011] SMI-Garbage

欧拉回路拆环

考虑在入栈的时候检查该元素是否在栈中,若在,表示成环。
注意:由于常见的求欧拉路的程序给出的结尾都不是开头点,所以在dfs调用后栈里面还剩下一个环,输出即可。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#define itra vector<int>::iterator

using namespace std;

const int N = 123456, M = 1234567;
int head[N], deg[N], ver[M<<1], vis[M<<1], nex[M<<1], tot;
inline void addedge(int u, int v) {
	ver[tot] = v; nex[tot] = head[u]; head[u] = tot++;
}

vector<int> va[N/10];
vector<int> sta;


int instack[N], vist[N], tt;
void dfs(int cur) {
	vist[cur] = 1;
	for(int i = head[cur]; ~i; i = nex[i])
		if(!vis[i]) {
			vis[i] = vis[i^1] = 1;
			head[cur] = nex[i];
			dfs(ver[i]);
			if(instack[ver[i]]) {
				va[tt].push_back(ver[i]);
				while(sta.back() != ver[i]) {
					va[tt].push_back(sta.back());
					instack[sta.back()] = 0;
					sta.pop_back();
				}
				va[tt].push_back(ver[i]);
				++tt;
			} else {
				sta.push_back(ver[i]);
				instack[ver[i]] = 1;
			}
		}
}

int main() {
	memset(head, -1, sizeof(head));
	int n, m, u, v, f, t, flg = 1;
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= m; ++i) {
		scanf("%d %d %d %d", &u, &v, &f, &t);
		if(f^t) {
			addedge(u, v); addedge(v, u);
			++deg[u]; ++deg[v];
		}
	}
 	for(int i = 1; i <= n; ++i) {
 		if(deg[i]%2) {
 			flg = 0;
 			break;
 		}
 	}
 	if(!flg) {
 		printf("NIE\n");
 		return 0;
	 }
	 for(int i = 1; i <= n; ++i) 
	 	if(!vist[i]) {
	 		dfs(i);
	 		if(instack[i]) {
	 			va[tt].push_back(i);
	 			while(!sta.empty()) {
	 				va[tt].push_back(sta.back());
	 				instack[sta.back()] = 0;
	 				sta.pop_back();
	 			}
	 			++tt;
	 		}
	 	}
	 printf("%d\n", tt);
	 for(int i = 0; i < tt; ++i) {
	 	printf("%d ", va[i].size()-1);
	 	for(itra it = va[i].begin(); it != va[i].end(); ++it) {
	 		printf("%d ", (*it));
	 	}
	 	printf("\n");
	 }
	return 0;
}