@codeforces - 1186F@ Vus the Cossack and a Graph
@description@
给定一个 n 点 m 边的图(n, m<=10^6),记第 i 个点的度数为 di。
现让你保留不超过 (n + m) / 2(向上取整)条边,并且要求新图中第 i 个点的度数 di' 满足 2di' ≥ di。
不难证明它一定有解。现你只需要输出任意一种方案。
input
第一行包含 n 和 m,表示点数与边数。
接下来 m 行每一行包含 2 个整数 ui, vi,描述一条边。
无重边、自环。
output
第一行首先输出保留的边的数量 k。
接下来 k 行每行两个整数 u, v,描述你所保留的边。
sample input
10 20
4 3
6 5
4 5
10 8
4 8
5 8
10 4
9 5
5 1
3 8
1 2
4 7
1 4
10 7
1 7
6 1
9 6
3 9
7 9
6 2
sample output
12
2 1
4 1
5 4
6 5
7 1
7 4
8 3
8 5
9 3
9 6
10 4
10 7
@solution@
好玄妙的题目啊。。。
但我想到的实现好像跟标算不大一样,不过用到的算法大致是一样的。
根据题目,偶数新度数最小为原度数的1/2,奇数新度数最小为(原度数+1)的1/2。
假如所有点的新度数都取最小值,则偶度点连接的边一半被删除,一半被保留;奇度点连接的某一条边保留,然后转为偶度点的情况。
这样将点的度数分奇偶讨论的过程,将某一个点连接的边分为相同大小的集合的操作,有没有让你联想到什么。
欧拉回路。即不重复、不遗漏经历所有边的路径。
欧拉回路可以将一个偶点连接的边分为“入边”和“出边”两类相同个数的边。
同时可以发现,以奇点开始奇点结束的欧拉路径,起点恰好多一条出边,终点恰好多一条入边。
这不和我们刚刚的讨论恰好相一致吗?
考虑欧拉回路,即没有奇数点的情况。
如果该欧拉回路长度为偶数,我们只需要隔一条边保留一条边即可,这样可以保证每一个点入边与出边保留恰好一条,且总边数减至一半。
否则如果长度为奇数,如 (1, 2), (2, 3), (3, 1),我们从第一条边开始隔一条边保留一条边,可以发现最后我们会同时保留第一条与最后一条,而这两条边是相邻的,故我们总边数变为原先的 1/2 再加 1 。
因为没有重边,长度为奇数必然包含两个以上的点,故最多会加 n/2 次。满足题设。
考虑欧拉路径,即起点和终点为奇数点的情况。
如果该欧拉回路长度为奇数,从起点开始隔一条边保留一条边即可。总边数变为原先的 1/2 加 1(因为奇数长度保留的要比删去的多一条)。
否则如果长度为偶数,如 (1, 2), (2, 3), (3, 4), (4, 5),我们从起点开始隔一条边保留一条边之后,再将与终点连接的边保留。总边数变为原先的 1/2 加 1。
最多会有 n 个奇数点,每两个奇数点之间产生一个路径,故最多会加 n/2 次。满足题设。
补充一小点:如何求解多条欧拉路径。你只需要将奇数点两两分组然后连接虚边,跑欧拉回路,然后两个虚边之间夹着的就是一条欧拉路径。如果没有虚边就是一条欧拉回路。
注意题目中给出的图可能不连通,你需要对每个连通块都进行操作。
@accepted code@
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 1000000;
const int MAXM = 5000000;
struct edge{
	int from, to;
	bool flag, tag;
	edge *nxt, *rev;
}edges[MAXM + 5], *adj[MAXN + 5], *ecnt = &edges[0];
int fa[MAXN + 5];
int find(int x) {
	return fa[x] = (fa[x] == x ? x : find(fa[x]));
}
void addedge(int u, int v, bool t) {
	edge *p = (++ecnt), *q = (++ecnt);
	p->from = u, p->to = v, p->nxt = adj[u], adj[u] = p;
	q->from = v, q->to = u, q->nxt = adj[v], adj[v] = q;
	p->flag = q->flag = false, p->tag = q->tag = t;
	p->rev = q, q->rev = p;
	if( find(u) != find(v) )
		fa[find(u)] = find(v);
}
int deg[MAXN + 5]; edge *e[MAXM + 5], *tmp[MAXM + 5];
int ans1[MAXM + 5], ans2[MAXM + 5];
int cnt, tot;
void dfs(int x) {
	for(edge *p=adj[x];p;p=adj[x]) {
		if( p->flag ) {
			adj[x] = adj[x]->nxt;
			continue;
		}
		p->flag = p->rev->flag = true;
		adj[x] = adj[x]->nxt; dfs(p->to); e[++cnt] = p;
	}
}
void print() {
	printf("%d\n", tot);
	for(int i=1;i<=tot;i++)
		printf("%d %d\n", ans1[i], ans2[i]);
}
int main() {
	int n, m; scanf("%d%d", &n, &m);
	for(int i=1;i<=n;i++)
		fa[i] = i;
	for(int i=1;i<=m;i++) {
		int u, v; scanf("%d%d", &u, &v);
		addedge(u, v, true); deg[u]++, deg[v]++;
	}
	int lst = 0, fir = 0;
	for(int i=1;i<=n;i++) {
		if( deg[i] & 1 ) {
			if( !lst ) lst = i;
			else addedge(lst, i, false), lst = 0;
		}
	}
	for(int i=1;i<=n;i++) {
		if( find(i) != i ) continue;
		cnt = lst = fir = 0; dfs(i);
		for(int j=1;j<=cnt;j++) {
			if( !e[j]->tag ) {
				if( lst ) {
					int siz = 0;
					for(int k=lst+1;k<=j-1;k++)
						tmp[++siz] = e[k];
					if( siz && siz % 2 == 0 ) tmp[siz+1] = tmp[siz], siz++;
					for(int k=1;k<=siz;k+=2)
						tot++, ans1[tot] = tmp[k]->from, ans2[tot] = tmp[k]->to;
					if( siz && siz % 2 == 0 )
						tot++, ans1[tot] = tmp[siz]->from, ans2[tot] = tmp[siz]->to;
				}
				else fir = j;
				lst = j;
			}
		}
		if( !lst ) {
			for(int j=1;j<=cnt;j+=2)
				tot++, ans1[tot] = e[j]->from, ans2[tot] = e[j]->to;
		}
		else {
			int siz = 0;
			for(int j=lst+1;j<=cnt;j++)
				tmp[++siz] = e[j];
			for(int j=1;j<=fir-1;j++)
				tmp[++siz] = e[j];
			if( siz && siz % 2 == 0 ) tmp[siz+1] = tmp[siz], siz++;
			for(int j=1;j<=siz;j+=2)
				tot++, ans1[tot] = tmp[j]->from, ans2[tot] = tmp[j]->to;
		}
	}
	print();
}
@details@
虽然题解里说的好像非常自然。
不过要是在做比赛的时候能想得到才有鬼好吧。
求欧拉路的时候通过打 tag 标记访问过的边会 TLE。需要类比网络流中的当前弧优化,将访问过的边直接删除。
@codeforces - 1186F@ Vus the Cossack and a Graph的更多相关文章
- Codeforces 1186F - Vus the Cossack and a Graph 模拟乱搞/欧拉回路
		题意:给你一张无向图,要求对这张图进行删边操作,要求删边之后的图的总边数 >= ceil((n + m) / 2), 每个点的度数 >= ceil(deg[i] / 2).(deg[i]是 ... 
- Codeforces F. Vus the Cossack and Numbers(贪心)
		题目描述: D. Vus the Cossack and Numbers Vus the Cossack has nn real numbers aiai. It is known that the ... 
- codeforces 1186C Vus the Cossack and Strings
		题目链接:https://codeforc.es/contest/1186/problem/C 题目大意:xxxxx(自认为讲不清.for instance) 例如:a="01100010& ... 
- CodeForces - 1186 C. Vus the Cossack and Strings (异或)
		Vus the Cossack has two binary strings, that is, strings that consist only of "0" and &quo ... 
- Vus the Cossack and Strings(Codeforces Round #571 (Div. 2))(大佬的位运算实在是太强了!)
		C. Vus the Cossack and Strings Vus the Cossack has two binary strings, that is, strings that consist ... 
- Codeforces Round #571 (Div. 2)-D. Vus the Cossack and Numbers
		Vus the Cossack has nn real numbers aiai. It is known that the sum of all numbers is equal to 00. He ... 
- Codeforces Round #485 (Div. 2) F. AND Graph
		Codeforces Round #485 (Div. 2) F. AND Graph 题目连接: http://codeforces.com/contest/987/problem/F Descri ... 
- Codeforces 1109D. Sasha and Interesting Fact from Graph Theory
		Codeforces 1109D. Sasha and Interesting Fact from Graph Theory 解题思路: 这题我根本不会做,是周指导带飞我. 首先对于当前已经有 \(m ... 
- CodeForces 840B - Leha and another game about graph   |  Codeforces Round #429(Div 1)
		思路来自这里,重点大概是想到建树和无解情况,然后就变成树形DP了- - /* CodeForces 840B - Leha and another game about graph [ 增量构造,树上 ... 
随机推荐
- mybatis添加数据返回主键
			程序结构图: 表结构: 创表sql: Create Table CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `us ... 
- bzoj4974: [Lydsy八月月赛]字符串大师
			传送门 题目可转换为已知一个串kmp之后的nxt数组,求字典序最小的原串. 已知第i位结尾的串循环节长度位x,那么nxt[i]=i-x; 当nxt不为0时,s[i]=s[nxt[i]]; nxt为0时 ... 
- 全球城市群Megalopolis
			Megalopolis From Wikipedia, the free encyclopedia (Redirected from Megalopolis (city type)) &quo ... 
- ip地址获取无效,自己修改ip地址
			(1) 
- 2-4 Numpy+Matplotlib可视化(二)
			自定义绘图 # -*-coding:utf-8-*- # !/usr/bin/env python # Author:@vilicute import numpy as np import matpl ... 
- 如何设置单个 Git 仓库的代理从而提高更新速度
			如何设置单个 Git 仓库的代理从而提高更新速度 因为特殊原因,需要单独对 Git 仓库设置远程代理,从而提高更新速度. 主要原因是因为有一些远程 Git 仓库比较慢. 最初的想法是系统全局代理,但是 ... 
- 移动项目到centos中运行报错:failed to open stream: Permission denied
			这是文件夹没有读写权限的错误: (注意:TP5.0权限给runtime文件夹就行了,官方文档在安装tp5的方法中有介绍到权限问题) 在需要赋予权限的文件夹的前一级输入: chmod -R 文件夹名字 
- vue 保存数组和对象, 避免双向绑定影响
			很多时候需要保存数据然后复用该数据,因vue的双向绑定总是不能保存原始数据 随笔记录解决方式 1. 不要把变量放置在data中 2. 保存至新的变量 object : let obj= Objec ... 
- Ajax之基础
			版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/liu_yujie2011com/article/details/29812777 几 ... 
- python LEGB原理简要介绍
