CF1186F

被诈骗了一个上午啊!但是想到了还是很妙的!

每个点至少要保留 degi2\left\lceil\dfrac{deg_i}{2}\right\rceil 条边,也就是一半左右。如果我们直接分配每个点,哪些边选哪些不选,发现这会影响很多东西,无法保证正确。

于是展开联想,选一半,如果有一条路径经过,入边和出边不同,是否就能满足条件了呢?

于是有一个初步的做法,每次 dfs 这个图,将路径上的边黑白交替染色。最后黑色边为答案。

但是有一个问题:如果有奇数度点怎么办?

再想想:一进一出,想到欧拉路。每次从一个奇数度点开始 dfs,一定会在另一个奇数度点结束。每次强制使第一条和最后一条边为黑,这样最多会比原来多 n2\left\lfloor\dfrac{n}{2}\right\rfloor 条黑边,最后在对只有偶数度的点的图 dfs 一遍。原来最多会有 m2\left\lceil\dfrac{m}{2}\right\rceil,加起来正好是 n+m2\le \left\lceil\dfrac{n+m}{2}\right\rceil 的!

在写这篇题解的时候突然产生了一个疑问:如果奇数度点数量顶满会不会出问题?事实上如果顶满了,最后那一遍 dfs 就不会进行,所以是没问题的。

非常巧(zha)妙(pian)的构造!非常好写。

code:

int n,m,deg[N];
bool vis[N],ans[N],pd[N];
vector<pii> g;
int tot,head[N];
struct node{
	int to,nxt;
}e[N<<1];
il void add(int u,int v){
	e[++tot]={v,head[u]},head[u]=tot;
}
void dfs(int u,int fl,int s,int lst){
	for(int &i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(vis[(i+1)/2]){
			continue;
		}
		vis[(i+1)/2]=1;
		ans[(i+1)/2]=fl;
		dfs(v,fl^1,s,(i+1)/2);
		return;
	}
	pd[u]=1;
	if(u!=s){
		ans[lst]=1;
	}
}
void Yorushika(){
	scanf("%d%d",&n,&m);
	rep(i,1,m){
		int u,v;scanf("%d%d",&u,&v);
		add(u,v),add(v,u);
		deg[u]++,deg[v]++;
	}
	rep(i,1,n){
		if((deg[i]&1)&&!pd[i]){
			dfs(i,1,i,0);
		}
	}
	rep(i,1,n){
		while(head[i]){
			dfs(i,1,i,0);
		}
	}
	rep(i,1,m){
		if(ans[i]){
			g.eb(e[i+i-1].to,e[i+i].to);
		}
	}
	printf("%d\n",g.size());
	for(auto [u,v]:g){
		printf("%d %d\n",u,v);
	}
}
signed main(){
	int t=1;
	//	scanf("%d",&t);
	while(t--)
		Yorushika();
}