习题: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;
}

猜你喜欢

转载自www.cnblogs.com/loney-s/p/13387979.html