现在你有一张无向图包含n个节点m条边。最初,每一条边都是蓝色或者红色。每一次你可以将一个节点连接的所有边变色(从红变蓝,蓝变红)。
找到一种步数最小的方案,使得所有边的颜色相同。
样例输入:
第一行包含两个数n,m分别代表节点数和边的数量
接下来m行描述边,第i行ui,vi,ci,代表ui有一条颜色为ci的边与vi相连(ci是B或者是R),B代表蓝色,R代表红色。数据保证没有自环的边。
3 3
1 2 B
3 1 R
3 2 B
样例输出:
如果没有方案就输出-1。否则第一行输出k代表最小的步数。
1
数据范围:
对于30%数据,n<=20,m<=20
100%:1<=n,m<=100000
……………………
画个图,捣鼓两种颜色中对于两个点的关系。
可以发现一个点最多只能被染一次,染了两次等于没染。
那么我们只需要分别求出都染成的红色和染成蓝色两种方案,选最优即可。
假设我们选择全部染成红色,那么对于一条红色的边,如果一端选择染色,那么另一端也必须要染色,所以这两个点必须归于一个集合。相反,对于蓝色的边,如果一端染色,那么另一端必定不能染色,这两个点便不能归于一个集合。
若一个点发生了冲突,那么这种情况下无解。
这道题就转化成了一个01图染色的问题。解决这种问题,自然就是运用BFS或DFS了,考虑道这道题数据有达到了 105 ,采用BFS可防止辣鸡电脑爆栈。
注意整个图不一定每个点都是联通的!
这打了我130行+,虽说有一半几乎是复制的。我旁边的童鞋用Pascal打了5000b+,我也是醉了。
#include
#include
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=100005;
int n,m,fre[maxn],next[maxn*2],go[maxn*2],color[maxn*2],num,bz[maxn];
void add(int x,int y,int z)
{
go[++num]=y;
next[num]=fre[x];
fre[x]=num;
color[num]=z;
}
int getred()
{
bool bk[maxn];
fo(i,1,n){
bz[i]=-1;
bk[i]=0;
}
int S=0,T=0,ans=0;
fo(p,1,n)
if (!bk[p]){
bk[p]=true;
bz[p]=0;
S=1;T=0;
int h=0,t=1,d[2*maxn+5];
d[1]=p;
while (h!=t){
h=h%(2*maxn+5)+1;
int u=d[h];
int i=fre[u];
while (i){
if (bz[go[i]]==-1){
if (color[i]==82) {
if (bz[u]==0) ++S;
else ++T;
bz[go[i]]=bz[u];
}
else{
bz[go[i]]=(bz[u]^1);
if (bz[u]==0) ++T;
else ++S;
}
t=t%(2*maxn+5)+1;
d[t]=go[i];
bk[go[i]]=true;
}
else{
if (bz[go[i]]==bz[u]&&color[i]==66) return -1;
if (bz[go[i]]!=bz[u]&&color[i]==82) return -1;
}
i=next[i];
}
}
ans=ans+min(S,T);
}
return ans;
}
int getblue()
{
bool bk[maxn];
fo(i,1,n){
bz[i]=-1;
bk[i]=0;
}
int S=0,T=0,ans=0;
fo(p,1,n)
if (!bk[p]){
bk[p]=true;
bz[p]=0;
S=1;T=0;
int h=0,t=1,d[2*maxn+5];
d[1]=p;
while (h!=t){
h=h%(2*maxn+5)+1;
int u=d[h];
int i=fre[u];
while (i){
if (bz[go[i]]==-1){
if (color[i]==66) {
if (bz[u]==0) ++S;
else ++T;
bz[go[i]]=bz[u];
}
else{
bz[go[i]]=(bz[u]^1);
if (bz[u]==0) ++T;
else ++S;
}
t=t%(2*maxn+5)+1;
d[t]=go[i];
bk[go[i]]=true;
}
else{
if (bz[go[i]]==bz[u]&&color[i]==82) return -1;
if (bz[go[i]]!=bz[u]&&color[i]==66) return -1;
}
i=next[i];
}
}
ans=ans+min(S,T);
}
return ans;
}
int main()
{
freopen("T2.in","r",stdin);
scanf("%d%d",&n,&m);
fo(i,1,m){
int x,y,colour;
scanf("%d%d",&x,&y);
colour=getchar();
colour=getchar();
add(x,y,colour);
add(y,x,colour);
}
int ans1=getred(),
ans2=getblue();
if (ans1==-1) printf("%d",ans2);
else if (ans2==-1) printf("%d",ans1);
else printf("%d",min(ans1,ans2));
fclose(stdin);
}