1. 程式人生 > 實用技巧 >習題:Graph Coloring(dfs)

習題:Graph Coloring(dfs)

題目

傳送門

思路

感覺這道題和2-SAT有點像

我們考慮確定第一個點是否翻轉和這個聯通塊的整體顏色為藍還是紅

之後我們就可以直接用一個dfs來確定是否無解

具體表現為通過一個點來確定與他相連的點是不是必須翻轉

考慮一條邊,如果兩個端點對於其他的邊都必須翻,但是兩個端點都翻轉卻會讓當前這條邊不合法

程式碼是真的醜,可能這就是蒟蒻吧

程式碼

#include<iostream>
#include<vector>
using namespace std;
namespace ufs
{
    int fa[100005];
    void makeset(int n)
    {
        for(int i=1;i<=n;i++)
            fa[i]=i;
    }
    int findset(int u)
    {
        if(fa[u]==u)
            return fa[u];
        return fa[u]=findset(fa[u]);
    }
    void unionset(int a,int b)
    {
        int u=findset(a);
        int v=findset(b);
        fa[u]=v;
    }
}
using namespace ufs;
struct node
{
    int e;
    int c;
};
int n,m;
int ans1,ans2;
int mem1[100005],mem2[100005],used[100005];
bool vis[100005];
vector<int> bel[100005];
vector<node> g[100005];
void init(int st)
{
    for(int i=0;i<bel[st].size();i++)
        used[bel[st][i]]=-1;
}
bool dfs(int u,int col)
{
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i].e;
        int edge_col=(g[u][i].c^used[u]);
        if(edge_col==col)
        {
            if(used[v]==1)
                return 0;
            if(used[v]==-1)
            {
                used[v]=0;
                if(dfs(v,col)==0)
                    return 0;
            }
        }
        else
        {
            if(used[v]==0)
                return 0;
            if(used[v]==-1)
            {
                used[v]=1;
                if(dfs(v,col)==0)
                    return 0;
            }
        }
    }
    return 1;
}
void update1(int st,int &ans)
{
    int tot=0;
    for(int i=0;i<bel[st].size();i++)
        if(used[bel[st][i]]==1)
            tot++;
    if(tot<ans)
    {
        ans=tot;
        for(int i=0;i<bel[st].size();i++)
            mem1[bel[st][i]]=used[bel[st][i]];
    }
}
void update2(int st,int &ans)
{
    int tot=0;
    for(int i=0;i<bel[st].size();i++)
        if(used[bel[st][i]]==1)
            tot++;
    if(tot<ans)
    {
        ans=tot;
        for(int i=0;i<bel[st].size();i++)
            mem2[bel[st][i]]=used[bel[st][i]];
    }
}
bool check1(int st)
{
    int ans=(1<<30);
    //翻轉
    init(st);
    used[st]=1;
    if(dfs(st,1))
        update1(st,ans);
    //不翻轉
    init(st);
    used[st]=0;
    if(dfs(st,1))
        update1(st,ans);
    if(ans==(1<<30))
        return 1;
    ans1+=ans;
    return 0;
}
bool check2(int st)
{
    int ans=(1<<30);
    //翻轉
    init(st);
    used[st]=1;
    if(dfs(st,0))
        update2(st,ans);
    //不翻轉
    init(st);
    used[st]=0;
    if(dfs(st,0))
        update2(st,ans);
    if(ans==(1<<30))
        return 1;
    ans2+=ans;
    return 0;
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;
    makeset(n);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        char c;
        cin>>u>>v>>c;
        g[u].push_back((node){v,c=='B'?1:0});
        g[v].push_back((node){u,c=='B'?1:0});
        unionset(u,v);
    }
    for(int i=1;i<=n;i++)
        bel[findset(i)].push_back(i);
    for(int i=1;i<=n;i++)
        if(vis[findset(i)]==0)
        {
            vis[findset(i)]=1;
            if(check1(findset(i)))
            {
                ans1=(1<<30);
                break;
            }
        }
    for(int i=1;i<=n;i++)
        vis[i]=0;
    for(int i=1;i<=n;i++)
        if(vis[findset(i)]==0)
        {
            vis[findset(i)]=1;
            if(check2(findset(i)))
            {
                ans2=(1<<30);
                break;
            }
        }
    if(ans1==(1<<30)&&ans2==(1<<30))
        cout<<"-1";
    else
    {
        if(ans1>ans2)
        {
            ans1=ans2;
            for(int i=1;i<=n;i++)
                mem1[i]=mem2[i];
        }
        cout<<ans1<<endl;
        for(int i=1;i<=n;i++)
            if(mem1[i]==1)
                cout<<i<<' ';
    }
    return 0;
}