CF 547 D. Mike and Fish

D. Mike and Fish

http://codeforces.com/contest/547/problem/D

题意:

  给定平面上n个点,将这些点染成红或者蓝色,要求每行、每列红色点与蓝色点数量的差的绝对值<=1。输出方案(保证有解)。

分析:

  参考popoqqq的博客

  将每行每列分别看做一个点,给定的每个点(x,y)拆成x->y的边,那么连边后的图是一个二分图。

  这样我们可以将边染色,使得与每个点相连的两种颜色差<=1。

  于是对于所有的欧拉回路,我们可以直接交替染色。

  但是会有度数为奇数的点,这样的点一定有偶数个,我们对其两两配对连边,这样所有奇度数的点度数就都为偶数了。

  对于每个连通块,选一个初始度数为奇数的点(若没有则任选度数为偶数的点),求一条欧拉回路(若是奇度数点则应先走与配对的奇度数点相连的边),将路径上的边交替染色即可。

正确性: 

  对于一条欧拉回路,除起点外每个点相连的红边与蓝边数是相同的。对于起点,欧拉回路的第一条边和最后一条边的颜色可能是相同的。

  若起点初始度数为奇数,由于先走了与新连出的边,所以就算第一条和最后一条边的颜色相同也没关系。(同色的话由于有影响的点在同行同列,一定连通,所以整个连通块只会额外多出一条边颜色不同)。

  若起点初始度数为偶数,则连通块是一个二分图,第一条和最后一条边的颜色一定不相同。

  还有一种神奇的做法:AOQNRMGYXLMVcaoyi0905

代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<cctype>
 7 #include<set>
 8 #include<vector>
 9 #include<queue>
10 #include<map>
11 #define fi(s) freopen(s,"r",stdin);
12 #define fo(s) freopen(s,"w",stdout);
13 using namespace std;
14 typedef long long LL;
15
16 inline int read() {
17     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch==‘-‘)f=-1;
18     for(;isdigit(ch);ch=getchar())x=x*10+ch-‘0‘;return x*f;
19 }
20
21 const int N = 400005;
22 const int D = 2e5;
23
24 struct Edge{
25     int to, nxt, id;
26 }e[N << 1];
27 int head[N], deg[N], A[N], sk[N], En = 1, top;
28 bool ve[N << 1], vd[N];
29 char ans[N];
30
31 void add_edge(int u,int v,int id) {
32     ++En; e[En].to = v, e[En].id = id, e[En].nxt = head[u]; head[u] = En;
33     ++En; e[En].to = u, e[En].id = id, e[En].nxt = head[v]; head[v] = En;
34     deg[u] ++, deg[v] ++;
35 }
36
37 void dfs(int u) {
38     vd[u] = true;
39     for (int i=head[u]; i; i=e[i].nxt) {
40         if (!ve[i]) {
41             ve[i] = ve[i ^ 1] = true; head[u] = i;
42             dfs(e[i].to);
43             sk[++top] = e[i].id; i = head[u];
44         }
45     }
46 }
47
48 int main() {
49     int n = read(), cnt = 0;
50     for (int i=1; i<=n; ++i) {
51         int u = read(), v = read() + D;
52         add_edge(u, v, i);
53     }
54     for (int i=1; i<=(D<<1); ++i)
55         if (deg[i] & 1) A[++cnt] = i;
56     for (int i=1; i<=cnt; i+=2)
57         add_edge(A[i], A[i + 1], 0);
58
59     for (int i=1; i<=cnt; ++i) {
60         if (!vd[A[i]]) {
61             dfs(A[i]);
62             while (top) ans[sk[top]] = top & 1 ? ‘b‘ : ‘r‘, top --;
63         }
64     }
65     for (int i=1; i<=(D<<1); ++i) {
66         if (!vd[i]) {
67             dfs(i);
68             while (top) ans[sk[top]] = top & 1 ? ‘b‘ : ‘r‘, top --;
69         }
70     }
71     ans[n + 1] = ‘\0‘;
72     puts(ans + 1);
73     return 0;
74 }

原文地址:https://www.cnblogs.com/mjtcn/p/9839274.html

时间: 2024-08-29 17:17:31

CF 547 D. Mike and Fish的相关文章

Codeforces 247D Mike and Fish

Mike and Fish 我们可以把这个模型转换一下就变成有两类点,一类是X轴, 一类是Y轴, 每个点相当于对应的点之间建一条边, 如果这条边变红两点同时+1, 变蓝两点同时-1. 我们能发现这个图其实是个二分图, 我们可以随便取一个点开始走路, 红蓝间隔开来,那么中间的点就权值不变, 对于最末尾的点虽然权值有改变,但是只会改变一次, 就这样一直走路直到所有的边都遍历完. #include<bits/stdc++.h> #define LL long long #define fi firs

CF Round410 D. Mike and distribution

D. Mike and distribution 构造法 798D - Mike and distribution In the beginning, it's quite easy to notice that the condition " 2·(ap1?+?...?+?apk) is greater than the sum of all elements in A " is equivalent to " ap1?+?...?+?apk is greater than

CF Round410 C. Mike and gcd problem

C. Mike and gcd problem 一奇一偶需要两次操作,两个奇数需要一次操作. 798D - Mike and distribution In the beginning, it's quite easy to notice that the condition " 2·(ap1?+?...?+?apk) is greater than the sum of all elements in A " is equivalent to " ap1?+?...?+?a

CF547D Mike and Fish 建图

题意: 有点长→CF547DMike and Fish. 分析: 其实也没什么好分析的,我这也是看的题解. (不过,那篇题解好像文字的代码不太对劲) 这里直接说做法,正确性自证: 对输入的,将横.纵坐标相等的点分别两两连边,之后只需要dfs跑一个染色,使得一条边两个端点颜色都不一样即可,这样就可以确定每一个点放红色还是蓝色,输出即可.(至于哪个是红哪个是蓝不重要,有spj) 代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 const

codeforces #305 D Mike and Fish

正解貌似是大暴搜? 首先我们考虑这是一个二分图,建立网络流模型后很容易得出一个算法 S->行 容量为Num[X]/2; 行->列 容量为1 且要求(x,y)这个点存在 列->T 容量为Num[Y]/2 这样子跑网络流之后我们就得到了一组解 但是我们考虑输出方案 对于每一行,如果Num[X]为偶数,那么显然输出方案是正确的 但是如果Num[x]为奇数,多出的那个显然既有可能是红的也可能是蓝的 但关键是我们不能确定他是红的或者蓝的,因为他的状态也会影响对应的列 同样,列的考虑也是同理 所以我

codeforces 547D Mike and Fish 欧拉路径

题目链接:点击打开链接 题意: 给定二维平面上的n个点的坐标 问: 把每个点用红色或蓝色染色, 使得 水平共线(或者垂直共线)的 点 中红色与蓝色数量差不超过1. 思路: 我们建一个二部图,X集是x轴,Y集是y轴 那么点(1,5)就是 x集的 1向 y集的 5连一条边. 此时点就是用边来表示的,那我们的任务就是给边染色. 使得: 对于二部图中任意一个点, 点所连接的红边和蓝边数量差不超过1. 那么我们可以认为这个点的入边就是红色,出边就是蓝色.显然这就是一个欧拉路径. 所以爆搜欧拉路径即可. #

codeforces #547D Mike and Fish 欧拉回路

题目大意:给定平面上的n个点,要求将每个点染成红色/蓝色,使得每行/每列的红色点数和蓝色点数之差≤1 将每一个横坐标/纵坐标看做一个点,每个点看做一条连接两个坐标的边 现在我们要将每条边染色使得每个点连接的所有边中两种颜色之差≤1 首先找到度数为奇数的点 这样的点一定有偶数个 将度数为奇数的点两两配对连边,这样所有点的度数就都是偶数了 然后对于每个连通块,任选一个初始度数为奇数的点(不存在则任选一个度数为偶数的点),求一条欧拉回路(如果起始点初始度数为奇数则要求先遍历新连接的边),然后将路径上的

cf547D. Mike and Fish(欧拉回路)

题意 题目链接 Sol 说实话这题我到现在都不知道咋A的. 考试的时候是对任意相邻点之间连边,然后一分没有 然后改成每两个之间连一条边就A了.. 按说是可以过掉任意坐标上的点都是偶数的数据啊.. #include<cstdio> #include<algorithm> #include<iostream> #include<vector> #include<cstring> #include<queue> #define Pair p

【CF 547E】 Mike and Friends

题目 显然SAM版题,写它的原因就是我太颓了:之后学习了一下正规的广义SAM写法,争取以后不再写lst=1 代码 #include<bits/stdc++.h> #define re register const int maxn=4e5+5; const int M=maxn*30; struct E{int v,nxt;}e[maxn];char S[maxn>>1]; int l[M],r[M],d[M],tot,q; int lst,cnt,n,L,num,dep[maxn