codeforces 662B Graph Coloring(搜索(2sat思想))

http://codeforces.com/problemset/problem/662/B 

题意:给你一个n点m边的无向图,每个边的颜色0或者1,然后让你对点进行操作,一次操作把这个点边上连着的边都变色,0变1,1变0,问你最少多少次能够把图变成一种颜色。不能就-1

题解:对于图的最后的颜色,我们可以假设最后颜色是0或者最后颜色是1,然后对于每条边的颜色,一个端点选择这个状态,另外个端点就必须是某个状态,这个感觉很像2sat,然而2sat输出这个最少操作的解的方法实在是不会写,而且两次2sat建图就能烦死人啊。

其实呢,你想把图变成一个颜色,然后对于一个连通分量里,你只要对第一个点确定状态,其他点的状态 就都确定了,所以直接对每个连通分量进行搜索,对第一个点进行操作或者不操作,然后把这个连通分量里其他点的状态都求出来,然后操作了的点就存起来,放到最后答案里,如果出现矛盾就这个染色方案不行咯

有点不好写,先需要假设图的颜色0或者1,然后对于连通分量的第一个点进行操作是0或者1,然后搜索,有解就存最少的,无解-1

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX           100005
#define   MAXN          1000005
#define   maxnode       10
#define   sigma_size    2
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair
#define   limit         10000

//const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 0x3f3f;
const double pi    = acos(-1.0);
const double inf   = 1e18;
const double eps   = 1e-9;
const LL     mod   = 1e9+7;
const ull    mxx   = 1333331;

/*****************************************************/
inline void RI(int &x) {
      char c;
      while((c=getchar())<'0' || c>'9');
      x=c-'0';
      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/

struct Edge{
    int v,next,c;
}edge[MAX*2];
int head[MAX];
int tot;
int flag[2];
vector<int> ans[2],temp[2];
int f[2];
int vis[MAX];
int col[MAX];
int n,m;

void init(){
    mem(head,-1);
    ans[0].clear();
    ans[1].clear();
    flag[0]=flag[1]=0;
    tot=0;
}

void add_edge(int a,int b,int c){
    edge[tot]=(Edge){b,head[a],c};
    head[a]=tot++;
}

void dfs(int x,int u,int op){
    vis[u]=1;
    col[u]=op;
    queue<int> q;
    q.push(u);
    vector<int> vv;
    while(!q.empty()){
        u=q.front();q.pop();
        vv.push_back(u);
        if(col[u]) temp[op].push_back(u);
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(vis[v]&&(edge[i].c^col[u]^col[v]!=x)){
                f[op]=1;
                break;
            }
            else if(!vis[v]){
                col[v]=edge[i].c^col[u]^x;
                vis[v]=1;
                q.push(v);
            }
        }
        if(f[op]) break;
    }
    if(op==0){
        for(int i=0;i<vv.size();i++){
            vis[vv[i]]=0;
        }
    }
}

void solve(int x){
    mem(vis,0);
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            temp[0].clear();temp[1].clear();//这个分量里面第一个点两种状态的需要操作的点的集合
            f[0]=f[1]=0;//两种状态的标记
            dfs(x,i,0);
            dfs(x,i,1);
            if(f[0]&&f[1]){
                flag[x]=1;//这种染色方案不可行
                return;
            }
            int k;
            if(f[0]) k=1;
            else if(f[1]) k=0;
            else if(temp[0].size()<temp[1].size()) k=0;
            else k=1;
            for(int j=0;j<temp[k].size();j++){
                ans[x].push_back(temp[k][j]);//整合这种染色方案的答案
            }
        }
    }
}
int main(){
    //freopen("in.txt","r",stdin);
    while(cin>>n>>m){
        init();
        for(int i=0;i<m;i++){
            int a,b;
            char c[10];
            scanf("%d%d%s",&a,&b,c);
            add_edge(a,b,(c[0]=='R'?0:1));
            add_edge(b,a,(c[0]=='R'?0:1));
        }
        solve(0);
        solve(1);
        if(flag[0]&&flag[1]) cout<<-1<<endl;
        else{
            int k;
            if(flag[0]) k=1;
            else if(flag[1]) k=0;
            else if(ans[0].size()<ans[1].size()) k=0;
            else k=1;
            cout<<ans[k].size()<<endl;
            for(int i=0;i<ans[k].size();i++){
                printf("%d",ans[k][i]);
                if(i==ans[k].size()-1) printf("\n");
                else printf(" ");
            }
        }
    }
    return 0;
}


 

你可能感兴趣的:(codeforces 662B Graph Coloring(搜索(2sat思想)))