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