Graph Coloring【NOIP2016提高A组模拟7.20】

题目:

现在你有一张无向图包含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);
}

Graph Coloring【NOIP2016提高A组模拟7.20】_第1张图片

你可能感兴趣的:(图论,染色)