Codeforces 664D Graph Coloring 二分图染色
题意:
一个无向图的每条边为红色或蓝色,有这样一种操作:每次选一个点,使与其相邻的所有边的颜色翻转。
求解是否可以经过一系列操作使所有的边颜色相同,并输出最少操作次数和相应的点。
分析:
每个点要么选要么不选,也就是对某个点最多进行一次这样的操作。
可以先假设把所有的边变为红色,然后逐个连通分量处理。
对每个连通分量的第一个点,继续枚举是选还是不选。
再根据边的当前颜色和目标颜色,确定相邻顶点选还是不选,相当于二分图染色的过程。
比较两种方案选的点的个数的多少,把较优的保存下来。
然后以把所有的边变成蓝色为目标,再进行一遍上面的过程,选出最优解。
方法二:
可以用TwoSAT求解,对于\((u,v)\)这条边:
- 如果变色的话,加上\(x\vee y\)和\(\bar{x} \vee \bar{y}\)两个条件
- 如果不变色的话,加上\(\bar{x} \vee y\)和\(x \vee \bar{y}\)两个条件
但是求最小解好像不太好写,=_=
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 100000 + 10;
const int INF = 10000000;
int n, m;
int head[maxn];
struct Edge
{
int v, c, nxt;
Edge() {}
Edge(int v, int c, int nxt) : v(v), c(c), nxt(nxt) {}
};
int ecnt;
Edge edges[maxn * 2];
void AddEdge(int u, int v, int c) {
edges[ecnt] = Edge(v, c, head[u]);
head[u] = ecnt++;
edges[ecnt] = Edge(u, c, head[v]);
head[v] = ecnt++;
}
vector<int> ans[2], t1, t2, cc;
bool vis[maxn], choose[maxn];
void find_cc(int u) {
cc.push_back(u);
vis[u] = true;
for(int i = head[u]; ~i; i = edges[i].nxt) {
int v = edges[i].v;
if(!vis[v]) find_cc(v);
}
}
bool dfs(int u, int c, vector<int>& t) {
vis[u] = true;
if(choose[u]) t.push_back(u);
for(int i = head[u]; ~i; i = edges[i].nxt) {
int v = edges[i].v;
if(vis[v] && (edges[i].c ^ choose[u] ^ choose[v] ^ c))
return false;
else if(!vis[v]) {
choose[v] = edges[i].c ^ c ^ choose[u];
if(!dfs(v, c, t)) return false;
}
}
return true;
}
int solve(int c, vector<int>& ans) {
memset(vis, false, sizeof(vis));
int cnt = 0;
for(int i = 1; i <= n; i++) if(!vis[i]) {
cc.clear();
find_cc(i);
for(int j = 0; j < cc.size(); j++) vis[cc[j]] = false;
t1.clear();
choose[i] = false;
bool ok1 = dfs(i, c, t1);
for(int j = 0; j < cc.size(); j++) vis[cc[j]] = false;
t2.clear();
choose[i] = true;
bool ok2 = dfs(i, c, t2);
for(int j = 0; j < cc.size(); j++) vis[cc[j]] = true;
if(!ok1 && !ok2) return INF;
vector<int>* t;
if(!ok1) t = &t2;
else if(!ok2) t = &t1;
else {
if(t1.size() < t2.size()) t = &t1;
else t = &t2;
}
ans.insert(ans.end(), (*t).begin(), (*t).end());
cnt += (*t).size();
}
return cnt;
}
void output(vector<int>& ans) {
for(int i = 0; i < ans.size(); i++) printf("%d ", ans[i]);
printf("\n");
}
int main()
{
ecnt = 0;
memset(head, -1, sizeof(head));
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++) {
int u, v;
char color;
scanf("%d %d %c", &u, &v, &color);
AddEdge(u, v, color == 'R');
}
int a = solve(0, ans[0]);
int b = solve(1, ans[1]);
if(a == b && a == INF) { printf("-1\n"); return 0; }
printf("%d\n", min(a, b));
if(a < b) output(ans[0]);
else output(ans[1]);
return 0;
}
Codeforces 664D Graph Coloring 二分图染色的更多相关文章
- Codeforces 1093D. Beautiful Graph【二分图染色】+【组合数】
<题目链接> 题目大意: 给你一个无向图(该无向图无自环,且无重边),现在要你给这个无向图的点加权,所加权值可以是1,2,3.给这些点加权之后,要使得任意边的两个端点权值之和为奇数,问总共 ...
- Graph Coloring I(染色)
Graph Coloring I https://www.nowcoder.com/acm/contest/203/J 题目描述 修修在黑板上画了一些无向连通图,他发现他可以将这些图的结点用两种颜色染 ...
- Codeforces 1093D Beautiful Graph(二分图染色+计数)
题目链接:Beautiful Graph 题意:给定一张无向无权图,每个顶点可以赋值1,2,3,现要求相邻节点一奇一偶,求符合要求的图的个数. 题解:由于一奇一偶,需二分图判定,染色.判定失败,直接输 ...
- HDU 5313 Bipartite Graph(二分图染色+01背包水过)
Problem Description Soda has a bipartite graph with n vertices and m undirected edges. Now he wants ...
- CodeForces 862B(思维+二分图染色)
题意 https://vjudge.net/problem/CodeForces-862B 给出n个点,n-1条边,求再最多再添加多少边使得二分图的性质成立 思路 因为题目是求的最多添加多少边,所以可 ...
- Codeforces 1499G - Graph Coloring(带权并查集+欧拉回路)
Codeforces 题面传送门 & 洛谷题面传送门 一道非常神仙的题 %%%%%%%%%%%% 首先看到这样的设问,做题数量多一点的同学不难想到这个题.事实上对于此题而言,题面中那个&quo ...
- UVA 193 Graph Coloring 图染色 DFS 数据
题意:图上的点染色,给出的边的两个点不能都染成黑色,问最多可以染多少黑色. 很水的一题,用dfs回溯即可.先判断和当前点相连的点是否染成黑色,看这一点是否能染黑色,能染色就分染成黑色和白色两种情况递归 ...
- Codeforces Round #550 (Div. 3) F. Graph Without Long Directed Paths (二分图染色)
题意:有\(n\)个点和\(m\)条无向边,现在让你给你这\(m\)条边赋方向,但是要满足任意一条边的路径都不能大于\(1\),问是否有满足条件的构造方向,如果有,输出一个二进制串,表示所给的边的方向 ...
- Educational Codeforces Round 56 (Rated for Div. 2) D. Beautiful Graph (二分图染色)
题意:有\(n\)个点,\(m\)条边的无向图,可以给每个点赋点权\({1,2,3}\),使得每个点连的奇偶不同,问有多少种方案,答案对\(998244353\)取模. 题解:要使得每个点所连的奇偶不 ...
随机推荐
- javascript动态修改对象的属性名
在做东钿业务系统的时候,经常碰到写很多重复的ajax对接,于是就想封装一个方法,但是接收data的字段名不一样,所以就需要用到动态对象属性名这个写法了.其实很简单.直接看一下代码吧.
- fancyBox高级进阶用法
最近给客户做的一个项目中,客户要求弹窗的边界与页面某个区块边界平齐,但平齐之后,弹出的窗口就不是居中的情况了,研究之后,认为需要改写fancyBox的fancybox-wrap类中的top属性才能达到 ...
- UVA 11990 ``Dynamic'' Inversion (线段树套BIT,分治)
题目要求可转化为查询一个区间内有多少数比val大(或者小). 区间用线段树分解(logN),每个区间维护一rank树. rank可用BIT查询,往BIT里面插值,为了保证不同区间的BIT互不影响要先离 ...
- fdisk - Linux分区表操作工具软件
总览 fdisk [-u]设备名 fdisk -l [-u] [设备名 ...] fdisk -s分区 ... fdisk -v 描述 硬盘可以被分成一个或多个逻辑磁盘,称为 分区. 这些分区信息都存 ...
- pip 安装出现异常
MacBookPro:~ mac$ pip install numpy Collecting numpy Downloading numpy-1.13.1-cp35-cp35m-macosx_10_6 ...
- C语言 数组名不是首地址指针
今天上计算机系统课的时候老师讲到了C中的聚合类型的数据结构.在解释数组名的时候说"数组名是一个指针,指向该数组的第一个元素",附上ppt(第二行): 我觉得这是不正确的,是一个常见 ...
- python_33_文件操作2
f=open('yesterday',encoding='utf-8') #print(f.readline())#读一行,并且是第一行 #读前5行 for i in range(5):#range( ...
- 基于纹理内存的CUDA热传导模拟
原文链接 项目中有三个,第一个是全局内存,其余两个分别是基于1d和2d纹理内存.项目打包下载. 纹理内存是只读内存,与常量内存相同的是,纹理内存也缓存在芯片中,因此某些情况下,它能减少对内存的请求并提 ...
- 委托、事件与Observer设计模式
范例说明 上面的例子已不足以再进行下面的讲解了,我们来看一个新的范例,因为之前已经介绍了很多的内容,所以本节的进度会稍微快一些: 假设我们有个高档的热水器,我们给它通上电,当水温超过95度的时候:1. ...
- java基础面试题:如何把一段逗号分割的字符串转换成一个数组? String s = "a" +"b" + "c" + "d";生成几个对象?
package com.swift; public class Douhao_String_Test { public static void main(String[] args) { /* * 如 ...