@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的更多相关文章

  1. Codeforces 1186F - Vus the Cossack and a Graph 模拟乱搞/欧拉回路

    题意:给你一张无向图,要求对这张图进行删边操作,要求删边之后的图的总边数 >= ceil((n + m) / 2), 每个点的度数 >= ceil(deg[i] / 2).(deg[i]是 ...

  2. 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 ...

  3. codeforces 1186C Vus the Cossack and Strings

    题目链接:https://codeforc.es/contest/1186/problem/C 题目大意:xxxxx(自认为讲不清.for instance) 例如:a="01100010& ...

  4. 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 ...

  5. 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 ...

  6. 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 ...

  7. Codeforces Round #485 (Div. 2) F. AND Graph

    Codeforces Round #485 (Div. 2) F. AND Graph 题目连接: http://codeforces.com/contest/987/problem/F Descri ...

  8. Codeforces 1109D. Sasha and Interesting Fact from Graph Theory

    Codeforces 1109D. Sasha and Interesting Fact from Graph Theory 解题思路: 这题我根本不会做,是周指导带飞我. 首先对于当前已经有 \(m ...

  9. CodeForces 840B - Leha and another game about graph | Codeforces Round #429(Div 1)

    思路来自这里,重点大概是想到建树和无解情况,然后就变成树形DP了- - /* CodeForces 840B - Leha and another game about graph [ 增量构造,树上 ...

随机推荐

  1. 【Django入坑之路】Models操作

    1:字段 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 pr ...

  2. CentOS7配置中文支持与部署GitLab服务器

    给你的 CentOS 7 安装中文支持 1.首先需要中文字体以便支持命令行终端的中文显示需求: yum groupinstall "fonts" 碰到提示输入 y 回车继续安装,大 ...

  3. oracle习题练习-表空间-用户-表-约束

    题一 1.       创建名字为hy_tablespace的表空间,默认大小为10M;@@ 2.       创建一个用户,用户名以自己名字命名,并指定命名空间为hy_tablespace;@@@@ ...

  4. Codeforces Round #304 (Div. 2) B. Soldier and Badges【思维/给你一个序列,每次操作你可以对一个元素加1,问最少经过多少次操作,才能使所有元素互不相同】

    B. Soldier and Badges time limit per test 3 seconds memory limit per test 256 megabytes input standa ...

  5. vue源码解读-目录结构

    目录结构 ├── scripts ------------------------------- 构建相关的文件,一般情况下我们不需要动│ ├── git-hooks ---------------- ...

  6. Provider Policy与Consumer Policy在bnd中的区别

    首先需要了解的是bnd的相关知识: 1. API(也就是接口), 2. API Provider(接口的实现) 3. API Consumer( 接口的使用者) OSGi中的一个版本有4个部分:    ...

  7. 第一次作业:reading and prepare

    这个作业属于哪个课程 课程的链接 这个作业要求在哪里 作业要求的链接 我在这个课程的目标是 理解软件开发流程,更好的开发自己的软件 这个作业在哪个具体方面帮助我实现目标 对"工程" ...

  8. Facebook POP 进阶指南

    本文转自Kevin Blog Facebook 在发布了 Paper 之后,似乎还不满足于只是将其作为一个概念性产品,更进一步开源了其背后的动画引擎 POP,此举大有三年前发布的 iOS UI 框架  ...

  9. Leetcode806.Number of Lines To Write String写字符串需要的行数

    我们要把给定的字符串 S 从左到右写到每一行上,每一行的最大宽度为100个单位,如果我们在写某个字母的时候会使这行超过了100 个单位,那么我们应该把这个字母写到下一行.我们给定了一个数组 width ...

  10. 2017 校赛 问题 E: 神奇的序列

    题目描述        Aurora在南宁发现了一个神奇的序列,即对于该序列的任意相邻两数之和都不是三的倍数.现在给你一个长度为n的整数序列,让你判断是否能够通过重新排列序列里的数字使得该序列变成一个 ...