Jzoj P4672 Graph Coloring___01图染色+dfs

版权声明:欢迎借鉴,谢绝抄搬。 https://blog.csdn.net/Gx_Man_VIP/article/details/88823266

题目大意:

一张n个节点m条边的无向图。
最初,每一条边都是蓝色或者红色。
每一次你可以将一个节点连接的所有边变色(从红变蓝,蓝变红)。
找到一种步数最小的方案,使得所有边的颜色相同。

1 < = n , m < = 100000 1<=n,m<=100000
没有自环的边

分析:

分别将边变为蓝色或者红色,然后取最优方案
因为每一个点最多改变一次,改变两次等于没有变化。
因此我们要将点分为两个集合 S 和 T,分别代表要改变的点和不需要改变的点。
然后类似于 2 S A T 2-SAT 的思想,
如果我们现在要将所有边变为红色,假设 u 和 v 之间有一条红色的边。如果要维持这种颜色,u 和 v 要属于同一个
集合(S 或者 T)。另一方面,如果这条边是蓝色,那么 u 和 v 就必须在两个不同的集合。
所以问题简化为了 0-1 图染色问题,可以用dfs解决。注意图不一定连通。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring>
#include <algorithm>

#define N 100005

using namespace std;

struct Node {
	int To, nxt, col;
}e[N*2];
int use[N], tot[2], ls[N], n, m, cnt, usecol;
bool check;

void Addedge(int u, int v, int w)
{
    e[++cnt].To = v, e[cnt].col = w, e[cnt].nxt = ls[u], ls[u] = cnt;
    e[++cnt].To = u, e[cnt].col = w, e[cnt].nxt = ls[v], ls[v] = cnt;
}

void dfs(int x)
{
	if (!check) return;
	tot[use[x]]++; 
	for (int i = ls[x]; i; i = e[i].nxt)
	{
		int now = e[i].col ^ use[x] ^ usecol;
		if (use[e[i].To] == -1)
		{
			use[e[i].To] = now;
			dfs(e[i].To);
			if (!check) return;
		} else if (use[e[i].To] != now) { check = 0; return; }
	}
}

// 红 1 蓝 0
 
int main()
{
	scanf("%d %d", &n, &m);
	int u, v; char w;
	for (int i = 1; i <= m; i++) 
	{
	    scanf("%d %d %c", &u, &v, &w);
		Addedge(u, v, (w == 'R'));
    }
    
    int ans1 = 0;
	memset(use, 255, sizeof(use)); usecol = 1; check = 1;
	for(int i = 1; i <= n; i++)
		if (use[i] == -1)
		{
			tot[1] = tot[0] = 0; use[i] = 1;
			dfs(i);
			ans1 += min(tot[0], tot[1]);
			if (!check) { ans1 = -1; break; } 
		}
	
	int ans2 = 0;
	memset(use, 255, sizeof(use)); usecol = 0; check = 1;
	for(int i = 1; i <= n; i++)
		if (use[i] == -1)
		{
			tot[1] = tot[0] = 0; use[i] = 1;
			dfs(i);
			ans2 += min(tot[0], tot[1]);
			if (!check) 
			{ 
			   if (ans1 == -1) printf("-1\n"); else printf("%d\n", ans1);
			   return 0;   
		    }
		}
	if (ans1 == -1) printf("%d\n", ans2); else printf("%d\n", min(ans1, ans2));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Gx_Man_VIP/article/details/88823266