题目大意:
题目链接:https://jzoj.net/senior/#main/show/4672
现在你有一张无向图包含个节点条边。最初,每一条边都是蓝色或者红色。每一次你可以将一个节点连接的所有边变色(从红变蓝,蓝变红)。
找到一种步数最小的方案,使得所有边的颜色相同。
思路:
记得以前做过费解的开关这道题,发现两道题蛮像的。
于是就用同样的思路去思考。
可以考虑先枚举其中一个点选择或不选择,以及最终要改成哪个颜色。如果我们已经把一条边上一个点修改了,那么如果要把这条边再次改回来,就只能把两另外一个点选择。但是你选择了这个点之后,又会有新的边被修改,然后依次类推。
所以,可以用一遍搜索来处理。如果经过若干次修改之后全部边都变成了一个颜色,那么就更新答案。
代码:
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int N=100010;
const int Inf=1e9;
int n,m,x,y,ans1,ans2,tot=1,head[N],father[N];
bool vis[N],used[N];
char ch;
struct edge
{
int next,to,col;
}e[N*2],a[N*2],b[N*2];
int find(int x)
{
return x==father[x]?x:father[x]=find(father[x]);
}
void add(int from,int to,int c)
{
e[++tot].to=to;
e[tot].col=c;
e[tot].next=head[from];
head[from]=tot;
}
bool check(int col)
{
for (register int i=2;i<=tot;i++)
if (a[i].col!=col) return 0;
return 1;
}
int work1(int S,int col,int change)
{
memset(vis,0,sizeof(vis));
queue<int> q;
vis[S]=1;
int cnt=change;
for (register int i=head[S];~i;i=a[i].next)
{
if (change)
a[i].col^=1,a[i^1].col^=1;
q.push(i);
}
while (q.size())
{
int j=q.front();
q.pop();
int u=a[j].to;
vis[u]=1;
if (a[j].col!=col)
{
cnt++;
for (register int i=head[u];~i;i=a[i].next)
{
a[i].col^=1;
a[i^1].col^=1;
int v=a[i].to;
if (vis[v]&&a[i].col!=col)
return Inf;
if (!vis[v]) q.push(i);
}
}
else
{
for (register int i=head[u];~i;i=a[i].next)
{
int v=a[i].to;
if (vis[v]&&a[i].col!=col)
return Inf;
if (!vis[v]) q.push(i);
}
}
}
return cnt;
}
int work2(int S,int col,int change)
{
memset(vis,0,sizeof(vis));
queue<int> q;
vis[S]=1;
int cnt=change;
for (register int i=head[S];~i;i=b[i].next)
{
if (change)
b[i].col^=1,b[i^1].col^=1;
q.push(i);
}
while (q.size())
{
int j=q.front();
q.pop();
int u=b[j].to;
vis[u]=1;
if (b[j].col!=col)
{
cnt++;
for (register int i=head[u];~i;i=b[i].next)
{
b[i].col^=1;
b[i^1].col^=1;
int v=b[i].to;
if (vis[v]&&b[i].col!=col)
return Inf;
if (!vis[v]) q.push(i);
}
}
else
{
for (register int i=head[u];~i;i=b[i].next)
{
int v=b[i].to;
if (vis[v]&&b[i].col!=col)
return Inf;
if (!vis[v]) q.push(i);
}
}
}
return cnt;
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for (register int i=1;i<=n;i++)
father[i]=i;
for (register int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
father[find(x)]=find(y);
while ((ch=getchar())&&ch!='R'&&ch!='B') ;
if (ch=='R')
{
add(x,y,1);
add(y,x,1);
}
else
{
add(x,y,0);
add(y,x,0);
}
}
memcpy(a,e,sizeof(e));
memcpy(b,e,sizeof(e));
for (register int i=1;i<=n;i++)
if (!used[find(i)])
{
int fa=find(i);
used[fa]=1;
ans1+=min(work1(fa,1,0),work2(fa,1,1));
if (ans1>=Inf) break;
}
memset(used,0,sizeof(used));
memcpy(a,e,sizeof(e));
memcpy(b,e,sizeof(e));
for (register int i=1;i<=n;i++)
if (!used[find(i)])
{
int fa=find(i);
used[fa]=1;
ans2+=min(work1(fa,0,0),work2(fa,0,1));
if (ans2>=Inf) break;
}
if (ans1>=Inf&&ans2>=Inf) printf("-1");
else printf("%d",min(ans1,ans2));
return 0;
}