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

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

思路1:模拟 + 乱搞

直接暴力删就行了,读入边之后随机打乱一下就很难被hack了。

代码:

#include <bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
#define db double
#define pii pair<int, int>
using namespace std;
const int maxn = 1000010;
struct node {
	int u, v, id;
};
vector<node> G;
int deg[maxn], limit[maxn], a[maxn];
pii b[maxn];
const LL mod = 1e9 + 7;
LL add(LL x, LL y) {return (x + y) % mod;}
LL mul(LL x, LL y) {return (x * y) % mod;}
bool vis[maxn];
bool cmp(int x, int y) {
	return deg[x] > deg[y];
}
int main() {
	int n, m, u, v;
	scanf("%d%d", &n, &m);
	int tot_limit = (n + m + 1) / 2;
	for (int i = 1; i <= m; i++) {
		scanf("%d%d", &u, &v);
//		G[u].push_back((node){u, v, i});
//		G[v].push_back((node){v, u, i});
		G.push_back((node){u, v, i});
		deg[u]++;
		deg[v]++;
	}
	for (int i = 1; i <= n; i++) {
		limit[i] = (deg[i] + 1) / 2;
	}
	random_shuffle(G.begin(), G.end());
	int ans = m;
	for (int j = 0; j < G.size() && ans > tot_limit; j++) {
		int v = G[j].v, now = G[j].u;
		if(deg[v] == limit[v]) continue;
		if(deg[now] == limit[now]) continue;
		vis[j] = 1;
		ans--;
		deg[v]--;
		deg[now]--;
	}
	printf("%d\n", ans);
	for (int i = 0; i < m; i++) {
		if(vis[i]) continue;
		printf("%d %d\n", G[i].u, G[i].v);
	}
}

思路2(官方题解):新建0号点,把0号点和图中所有度数为奇数的点相连,形成一张新图。在新图上跑一遍欧拉回路,把欧拉回路记录的边中偶数位置的删掉,删的时候如果是新加的边,就直接删了。否则,看一下这条边相邻的两条边是不是新加的边并且可以删,如果可以,那就删新加的边,否则删这条边。即迫不得已的情况才会删除原图的边。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000010;
struct edge {
	int u, v, flag;
};

int st[maxn * 2], ans[maxn * 2], re[maxn * 2];
edge a[maxn * 2];
int head[maxn], id[maxn * 4], Next[maxn * 4], ver[maxn * 4], tot, totm, tot_ans;
bool v[maxn * 4], vis[maxn * 4];
int deg[maxn];
int Top;
void add(int x, int y, int z) {
	ver[++tot] = y, id[tot] = z, Next[tot] = head[x], head[x] = tot;
}
void euler (int s) {
	tot_ans = 0;
	st[++Top] = s;
	while(Top > 0) {
		int x = st[Top], i = head[x];
		while(i && v[i]) i = Next[i];
		if(i) {
			st[++Top] = ver[i];
			re[Top] = id[i];
			v[i] = v[i ^ 1] = 1;
			head[x] = Next[i];
		} else {
			ans[++tot_ans] = re[Top];
			Top--;
		}
	}
}
int main() {
	int n, m, x, y;
	scanf("%d%d", &n, &m);
	tot = 1;
	for (int i = 1; i <= m; i++) {
		scanf("%d%d", &x, &y);
		totm++;
		a[totm] = (edge){x, y, 1};
		add(x, y, totm), add(y, x, totm);
		deg[x]++, deg[y]++;
	}
	for (int i = 1; i <= n; i++) {
		if(deg[i] & 1) {
			totm++;
			a[totm] = (edge){0, i, 0};
			add(0, i, totm), add(i, 0, totm);
		}
	}
	int res = m;
	for (int i = 0; i <= n; i++) {
		euler(i);
		for (int j = 2; j <= tot_ans; j += 2) {
			int now = ans[j];
			if(a[now].flag == 0) vis[now] = 1;
			else {
				int tmp = ans[j - 1];
				if(a[tmp].flag == 0 && vis[tmp] == 0) {
					vis[tmp] = 1;
					continue;
				}
				int Next = j + 1;
				if(j == tot_ans) Next = 1;
				tmp = ans[Next];
				if(a[tmp].flag == 0 && vis[tmp] == 0) {
					vis[tmp] = 1;
					continue;
				}
				vis[now] = 1;
				res--;
			}
		}
	}
	printf("%d\n", res);
	for (int i = 1; i <= totm; i++) {
		if(vis[i] == 0) {
			if(a[i].flag == 1) {
				printf("%d %d\n", a[i].u, a[i].v);
			}
		}
	}
}
//6 6
//3 4
//4 5
//5 3
//1 3
//1 2
//2 3

原文地址:https://www.cnblogs.com/pkgunboat/p/11106317.html

时间: 2024-12-09 05:17:25

Codeforces 1186F - Vus the Cossack and a Graph 模拟乱搞/欧拉回路的相关文章

Codeforces Gym 100496J(模拟乱搞,线段相交)

题意:给一个M*N的矩形区域,有M*N个方格,有些方格为空(可到达),有些非空(不可达).现A和B在博弈,他们任选两个不同的空格,站在各自的格子中央,A可以移动,但只能进行一次行方向或列向方移动,移动后仍然在格子中央.A如果移动到一个位置使得B看不见他,则A获胜.B看不见A的条件是存在一个非空格子与B到A的线段相切或相交.问,对于每个空格子,A站在上面,是否无论B在哪里,他都可以移动到一个安全位置. A可以选择不移动,题目保证至少有两个空格子,每次移动只能进行横向或竖向移动,不能都进行.空格子内

Codeforces Round #445 div.2 D. Restoration of string 乱搞

D. Restoration of string 题意:给你n个字符串,让你构造一个终串,使得这n个字符串都是终串的最小频繁子串,如果不存在输出NO.  最频繁子串:出现次数最多的子串 tags: 直接暴力怼?? #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a;

CodeForces 21D Traveling Graph 状压dp+欧拉回路

题目链接:点击打开链接 题意: 给定n个点m条边的无向图 求从1点开始经过每条边至少一次最后回到1点的最小路程 显然就是找一条路径可重复的欧拉回路 思路: 首先对于欧拉回路的结论是:所有点的度数都为偶数 因为所有边至少经过一次,那么可以把题意转换成加最少多少条边使得图满足以上结论 而加的边目的是为了把奇度数转成偶度数,先floyd一下得到任意点间加边的最小花费 dp[i]表示状态i下度数都为偶数的最小花费. 状压dp,把i状态下,所有未选择的点中挑2个奇度数的转移即可. #include <cs

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

思路来自这里,重点大概是想到建树和无解情况,然后就变成树形DP了- - /* CodeForces 840B - Leha and another game about graph [ 增量构造,树上差分 ] | Codeforces Round #429(Div 1) 题意: 选择一个边集合,满足某些点度数的奇偶性 分析: 将d = 1的点连成一颗树,不在树上的点都不连边. 可以发现,当某个节点u的所有子节点si均可操控 (u, si) 来满足自身要求 即整棵树上至多只有1个点不满足自身要求,

Codeforces Round #261 (Div. 2)——Pashmak and Graph

题目链接 题意: n个点,m个边的有向图,每条边有一个权值,求一条最长的路径,使得路径上边值严格递增.输出路径长度 (2?≤?n?≤?3·105; 1?≤?m?≤?min(n·(n?-?1),?3·105)) 分析: 因为路径上会有重复点,而边不会重复,所以最开始想的是以边为状态进行DP,get TLE--后来想想,在以边为点的新图中,边的个数可能会很多,所以不行. 考虑一下裸的DP如何做:路径上有重复点,可以将状态详细化,dp[i][j]表示i点以j为结束边值的最长路,但是数据不允许这样.想想

Codeforces 216D Spider&#39;s Web 树状数组+模拟

题目链接:http://codeforces.com/problemset/problem/216/D 题意: 对于一个梯形区域,如果梯形左边的点数!=梯形右边的点数,那么这个梯形为红色,否则为绿色, 问: 给定的蜘蛛网中有多少个红色. 2个树状数组维护2个线段.然后暴力模拟一下,因为点数很多但需要用到的线段树只有3条,所以类似滚动数组的思想优化内存. #include<stdio.h> #include<iostream> #include<string.h> #in

Codeforces 439C Devu and Partitioning of the Array(模拟)

题目链接:Codeforces 439C Devu and Partitioning of the Array 题目大意:给出n个数,要分成k份,每份有若干个数,但是只需要关注该份的和为奇数还是偶数,要求偶数堆的个数为p.输出方案. 解题思路:首先先将数组按照奇偶排序,也可以分开储存.然后先单独分k-p个奇数,然后后面的就将两个奇数当一个偶数分配,分配过程中计算是否满足,比如说奇数是否成对,以及是否分成了k堆. #include <cstdio> #include <cstring>

@codeforces - [email&#160;protected] Vus the Cossack and a Field

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 给定一个 n*m 的 01 矩阵,通过这个矩阵生成一个无穷矩阵,具体操作如下: (1)将这个矩阵写在左上角. (2)将这个矩阵每位取反写在右上角. (3)将这个矩阵每位取反写在左下角. (4)将这个矩阵写在右下角. (5)将得到的矩阵再作为初始矩阵,重复这些操作. 比如对于初始矩阵:

Codeforces 841D Leha and another game about graph - 差分

Leha plays a computer game, where is on each level is given a connected graph with n vertices and m edges. Graph can contain multiple edges, but can not contain self loops. Each vertex has an integer di, which can be equal to 0, 1 or  - 1. To pass th