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;
}