CF1186 F. Vus the Cossack and a Graph
题目传送门:https://codeforces.com/problemset/problem/1186/F
题目大意:
给一个\(n\)点\(m\)条边的无向简单图\(G\),记\(d_i\)为点\(i\)的度数。你需要在其中找到一个子图\(Z\),满足\(Z\)的边数\(m_Z\leqslant \lceil\frac{n+m}{2}\rceil\),记\(f_i\)为\(Z\)中点\(i\)的度数,满足\(\forall i\in G,\lceil\frac{d_i}{2}\rceil\leqslant f_i\)
求子图\(Z\)
解法一(暴力+人品):将所有边存下来后随机打乱,然后判断端点度数是否满足\(\lfloor\frac{d_i}{2}\rfloor\leqslant f_i\),进行加边与否的操作即可
解法二(正解):
-
所有点的度数都是偶数,说明该图存在欧拉回路,我们求出欧拉回路,然后间隔保留\(\frac{m}{2}\)条边,这样即可保证所有点的度数恰好为\(f_i=\frac{d_i}{2}\)
-
存在部分点的度数为奇数,我们可以新建0号节点,向所有度数为奇数的点连边(虚边)。显然,这些点的数量为偶数,故新图所有点的度数都为偶数
给新图求欧拉回路后,虚边会将回路分割成若干部分。若该段边数为偶数,则按上一种情况处理;如果该段边数为奇数,则保留两端的边,中间再间隔保留。因为两端的点的度数为奇数,需要多保留一位
/*program from Wolfycz*/
#include<map>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Fi first
#define Se second
#define ll_inf 1e18
#define MK make_pair
#define sqr(x) ((x)*(x))
#define pii pair<int,int>
#define int_inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>inline T frd(T x){
int f=1; char ch=gc();
for (;ch<'0'||ch>'9';ch=gc()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
template<typename T>inline T read(T x){
int f=1; char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline void print(int x){
if (x<0) putchar('-'),x=-x;
if (x>9) print(x/10);
putchar(x%10+'0');
}
const int N=1e6;
int pre[(N<<2)+10],now[N+10],child[(N<<2)+10],vis[(N<<2)+10];
int stack[(N<<2)+10],Ans[N+10][2],D[N+10],Cur[N+10],top,n,m,Cnt,tot=1;
void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
void insert(int x,int y){join(x,y),join(y,x);}
void Dfs(int x,int Fr){
for (;Cur[x];){
int p=Cur[x]; Cur[x]=pre[Cur[x]];
if (vis[p]) continue;
vis[p]=vis[p^1]=1;
Dfs(child[p],p);
}
if (Fr) stack[++top]=Fr;
}
void solve(){
for (int i=1,Last=0;i<=top+1;i++){
if (i>top||stack[i]>(m<<1)+1){
for (int j=Last+1;j<i;j+=2){
Ans[++Cnt][0]=child[stack[j]];
Ans[Cnt][1]=child[stack[j]^1];
}
if ((i-Last)%2&&Last+1<i){
Ans[++Cnt][0]=child[stack[i-1]];
Ans[Cnt][1]=child[stack[i-1]^1];
}
Last=i;
}
}
}
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n=read(0),m=read(0);
for (int i=1;i<=m;i++){
int x=read(0),y=read(0);
D[x]++,D[y]++;
insert(x,y);
}
for (int i=1;i<=n;i++) if (D[i]&1) insert(0,i);
for (int i=0;i<=n;i++) Cur[i]=now[i];
for (int i=0;i<=n;i++){
top=0,Dfs(i,0);
solve();
}
printf("%d\n",Cnt);
for (int i=1;i<=Cnt;i++)
printf("%d %d\n",Ans[i][0],Ans[i][1]);
return 0;
}