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

来源:互联网 发布:淘宝店铺负责人更改 编辑:程序博客网 时间:2024/06/13 11:50

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;}


 

0 0