题意:
给定一个(n)个点(m)条边的无向图,定义(d_i)为第(i)个点的度数。
现在要去掉一些边,使得最后保留(displaystylelceilfrac{n+m}{2}
ceil)条边。
定义(f_i)为最终图中点的度数,那么满足对于(1leq ileq n),都有(displaystylelceilfrac{d_i}{2}
ceilleq f_i)。
输出最后保留的边。
思路:
- 若(mleq n),显然直接保留所有的边即可;
- 若(m>n),发现我们只需要去掉所有的环即可满足条件。注意到一个环中我们肯定可以去掉一条边使得度数满足条件,那么也就是可以去掉所有的环。
- 那么通过(dfs)构建(dfs)树直接去环即可。
- 只进行一次(dfs)的话可能会因为度数限制不能去掉所有的环,那么我们只需要随机选取若干次起点去环即可。
至于正确性的证明不是很会,但感觉应该可以在满足度数限制的条件下去掉所有的环。
如果有大佬知道的话希望能够不吝赐教。
代码如下:
/*
* Author: heyuhhh
* Created Time: 2020/3/19 20:57:08
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#include <random>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '
'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e6 + 5;
int n, m;
struct Edge {
int u, v;
} edges[N];
vector <pii> G[N];
vector <int> res;
bool chk[N], out[N];
int d[N], f[N];
void dfs(int u, int fa) {
chk[u] = true;
for(auto it : G[u]) if(it.fi != fa) {
int v = it.fi, i = it.se;
if(out[i]) continue;
if(chk[v]) {
if(f[u] - 1 >= (d[u] + 1) / 2 && f[v] - 1 >= (d[v] + 1) / 2) {
out[i] = true;
--f[u], --f[v];
}
continue;
}
dfs(v, u);
}
}
mt19937 rnd(time(NULL));
void run() {
cin >> n >> m;
for(int i = 1; i <= m; i++) {
int u, v; cin >> u >> v;
G[u].push_back(MP(v, i));
G[v].push_back(MP(u, i));
edges[i] = Edge {u, v};
++d[u], ++d[v];
}
for(int i = 1; i <= n; i++) f[i] = d[i];
if(m <= n) {
cout << m << '
';
for(int i = 1; i <= m; i++) {
cout << edges[i].u << ' ' << edges[i].v << '
';
}
} else {
for(int i = 1; i <= 20; i++) {
memset(chk, false, sizeof(chk));
int rt = rnd() % n + 1;
dfs(rt, 0);
}
for(int i = 1; i <= m; i++) if(!out[i]) res.push_back(i);
cout << sz(res) << '
';
for(auto it : res) {
cout << edges[it].u << ' ' << edges[it].v << '
';
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}