2018 Multi-University Training Contest 2 03

题意

给定 \(n\) 个点 \(m\) 条边无向图。
问最少多少条路径能恰好覆盖每条边一次。

\(1\ \leq\ n,\ m\ \leq\ 10^5\)

做法1

对于一个联通块,将奇数度数点两两匹配,然后跑欧拉路,删去新加的边,可以证明不会更优。时间复杂度 \(O(n\ +\ m)\)

代码

#include <bits/stdc++.h>

#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif

#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif

using namespace std;

const int maxn = 1e5 + 10, maxm = 5e5 + 10;

int n, m, par[maxn], e_n, iter[maxn];
vector<pair<int, int> > g[maxn], all;
vector<vector<int> > ans;
vector<int> cur, t;
bool vis[maxm];

int F(int u) { return par[u] == u ? u : par[u] = F(par[u]); }

void dfs(int u) {
	for (int j, &i = iter[u]; i < g[u].size(); ++i) if(!vis[abs(j = g[u][i].second)]) {
		vis[abs(j)] = 1;
		dfs(g[u][i].first);
		cur.push_back(j);
	}
	return;
}

void solve() {
	ans.clear(); all.clear(); cur.clear();
	for (int u = 1; u <= n; ++u) g[u].clear(), par[u] = u, iter[u] = 0;
	for (int i = 1; i <= m; ++i) {
		int u, v;
		scanf("%d%d", &u, &v);
		g[u].push_back(make_pair(v, i));
		g[v].push_back(make_pair(u, -i));
		par[F(u)] = F(v);
	}
	for (int u = 1; u <= n; ++u) if(g[u].size() & 1) all.push_back(make_pair(F(u), u));
	sort(all.begin(), all.end());
	e_n = m;
	for (int i = 0; i < all.size(); i += 2) {
		int u = all[i].second, v = all[i + 1].second;
		++e_n;
		g[u].push_back(make_pair(v, e_n));
		g[v].push_back(make_pair(u, -e_n));
	}
	memset(vis, 0, sizeof(vis[0]) * (e_n + 1));
	for (int u = 1; u <= n; ++u) {
		if(iter[u] < g[u].size()) {
			cur.clear();
			dfs(u);
			reverse(cur.begin(), cur.end());
			int i = 0;
			while(i < cur.size() && abs(cur[i]) <= m) ++i;
			if(i == cur.size()) ans.push_back(cur);
			else {
				t.clear();
				for (int j = i + 1; j < cur.size(); ++j) {
					int x = cur[j];
					if(abs(x) > m) {
						if(t.size()) ans.push_back(t), t.clear();
					}
					else t.push_back(x);
				}
				for(int j = 0; j <= i; ++j) {
					int x = cur[j];
					if(abs(x) > m) {
						if(t.size()) ans.push_back(t), t.clear();
					}
					else t.push_back(x);
				}
			}
		}
	}
	printf("%d\n", ans.size());
	for (int i = 0; i < ans.size(); ++i) {
		printf("%d", ans[i].size());
		for (int j = 0; j < ans[i].size(); ++j) printf(" %d", ans[i][j]);
		puts("");
	}
	return;
}

int main() {
	while(scanf("%d%d", &n, &m) == 2) solve();
	return 0;
}
posted @ 2018-09-09 16:40  King_George  阅读(87)  评论(0编辑  收藏  举报