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;
}
posted @ 2021-07-08 15:53  Wolfycz  阅读(57)  评论(0编辑  收藏  举报