You are given an undirected graph that consists of n vertices and m edges. Initially, each edge is colored either red or blue. Each turn a player picks a single vertex and switches the color of all edges incident to it. That is, all red edges with an endpoint in this vertex change the color to blue, while all blue edges with an endpoint in this vertex change the color to red.
Find the minimum possible number of moves required to make the colors of all edges equal.
The first line of the input contains two integers n and m (1 ≤ n, m ≤ 100 000) — the number of vertices and edges, respectively.
The following m lines provide the description of the edges, as the i-th of them contains two integers ui and vi (1 ≤ ui, vi ≤ n, ui ≠ vi) — the indices of the vertices connected by the i-th edge, and a character ci () providing the initial color of this edge. If ciequals 'R', then this edge is initially colored red. Otherwise, ci is equal to 'B' and this edge is initially colored blue. It's guaranteed that there are no self-loops and multiple edges.
If there is no way to make the colors of all edges equal output - 1 in the only line of the output. Otherwise first output k — the minimum number of moves required to achieve the goal, then output k integers a1, a2, ..., ak, where ai is equal to the index of the vertex that should be used at the i-th move.
If there are multiple optimal sequences of moves, output any of them.
3 3
1 2 B
3 1 R
3 2 B
1
2
6 5
1 3 R
2 3 R
3 4 B
4 5 R
4 6 R
2
3 4
4 5
1 2 R
1 3 R
2 3 B
3 4 B
1 4 B
-1
题意:
给你n个点m条边,每条边有一种颜色(B或R),每选择一个点可以使与其相连的所有边的颜色翻转,问最少需要选择多少个点,使得所有边的颜色相同,输出操作数以及操作哪些点。
(1 ≤ n,m ≤ 100000)
思路:
我们可以分别对把所有边变成B和R分别考虑。
因为每个点不会操作2次或者更多,因为操作两次相当于不操作,操作三次相当于操作一次。
下面有两种方法:
一:暴搜
假设你选择了一个点翻转或者不翻转,那么与其在同一个联通块中的其他的所有点翻转或者不翻转也便确定了。
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <ctime> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define INF 0x3f3f3f3f #define inf -0x3f3f3f3f #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define mem0(a) memset(a,0,sizeof(a)) #define mem1(a) memset(a,-1,sizeof(a)) #define mem(a, b) memset(a, b, sizeof(a)) typedef long long ll; const int maxn=200100; const int maxm=3*maxn; typedef pair<int,int> PI; vector<PI>G[maxn]; vector<int>mp; int vis[maxn],vis1[maxn],ans1,ans; int vis2[maxn],vis3[maxn]; bool dfs(int u,int num){ for(int i=0;i<G[u].size();i++){ int v=G[u][i].first,w=G[u][i].second; if(vis[v]!=0){ if(w==num){ if(vis[u]!=vis[v]) return false; continue; } else{ if(vis[u]==vis[v]) return false; continue; } } if(w==num){ vis[v]=vis[u]; mp.push_back(v); if(vis[v]==2) ans1++; if(!dfs(v,num)) return false; } else{ vis[v]=3-vis[u]; mp.push_back(v); if(vis[v]==2) ans1++; if(!dfs(v,num)) return false; } } return true; } void solve(int n,int num){ mem0(vis),mem0(vis1),mem0(vis2); mp.clear(); int ANS=0; for(int i=1;i<=n;i++){ //变为B if(vis1[i]==1) continue; ans1=0,vis[i]=1;//为0表示不翻转 int flag1=0,flag2=0; mp.push_back(i); if(dfs(i,num))//B标记为1,这个点不翻转 flag1=1; for(int j=0;j<mp.size();j++){ vis2[mp[j]]=(vis[mp[j]]==2 ? 1:0); vis[mp[j]]=0; vis1[mp[j]]=1; } int Ans1=ans1; mp.clear(); mp.push_back(i); ans1=1,vis[i]=2;//为1表示翻转 if(dfs(i,num))//B标记为1,这个点不翻转 flag2=1; int Ans2=ans1; for(int j=0;j<mp.size();j++) vis1[mp[j]]=1; if(flag1==1&&flag2==1){ if(Ans1<Ans2) ANS+=Ans1; else{ ANS+=Ans2; for(int j=0;j<mp.size();j++) vis2[mp[j]]=(vis[mp[j]]==2 ? 1:0); } } else if(flag1==1) ANS+=Ans1; else if(flag2==1){ ANS+=Ans2; for(int j=0;j<mp.size();j++) vis2[mp[j]]=(vis[mp[j]]==2 ? 1:0); } else{ ANS=INF; break; } mp.clear(); } if(ANS<ans){ for(int i=1;i<=n;i++) vis3[i]=vis2[i],ans=ANS; } } int main(){ int n,m; scanf("%d%d",&n,&m); int u,v; char s[2]; for(int i=0;i<m;i++){ scanf("%d%d%s",&u,&v,s); if(s[0]=='B'){ G[u].push_back(PI{v,1}); G[v].push_back(PI{u,1}); } else{ G[u].push_back(PI{v,2}); G[v].push_back(PI{u,2}); } } ans=INF; solve(n,1); solve(n,2); if(ans==INF) puts("-1"); else{ printf("%d\n",ans); for(int i=1;i<=n;i++) if(vis3[i]==1) printf("%d ",i); printf("\n"); } }
二:
用2-sat强连通模板跑
假设现在要把所有边变成R,现在有u,v两点之间的边为B,
我们用v+n,u+n表示这两个点不翻转,u,v表示这两个点进行翻转
则我们可以建立以下四条边
u->v+n,v+n->u,u+n->v,v->u+n
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <ctime> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define INF 0x3f3f3f3f #define inf -0x3f3f3f3f #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define mem0(a) memset(a,0,sizeof(a)) #define mem1(a) memset(a,-1,sizeof(a)) #define mem(a, b) memset(a, b, sizeof(a)) typedef long long ll; const int maxn=200100; const int maxm=3*maxn; typedef pair<int,int> PI; vector<PI>G[maxn]; vector<int>mp[maxn]; int ans; struct Edge{ int to,next; }e[maxm]; int head[maxn],tot; void init(){ tot=0; mem1(head); } void addedge(int from,int to){ e[tot].to=to; e[tot].next=head[from]; head[from]=tot++; } int Low[maxn],DFN[maxn],Stack[maxn],Belong[maxn],num[maxn]; int Index,top,scc; bool Instack[maxn]; int flag[maxn],vis[maxn]; void Tarjan(int u,int n){ int v; Low[u]=DFN[u]=++Index; Stack[top++]=u; Instack[u]=true; for(int i=head[u];i!=-1;i=e[i].next){ v=e[i].to; if(!DFN[v]){ Tarjan(v,n); if(Low[u]>Low[v]) Low[u]=Low[v]; } else if(Instack[v]&&Low[u]>DFN[v]) Low[u]=DFN[v]; } if(Low[u]==DFN[u]){ scc++; do{ v=Stack[--top]; Instack[v]=false; Belong[v]=scc; if(v<=n) num[scc]++; mp[scc].push_back(v); }while(v!=u); } } void solve(int n,int C){ //CΪ1��ʾ��ΪB,CΪ2��ʾ��ΪR for(int i=0;i<2*n;i++) mp[i].clear(); init(); mem0(DFN); mem0(Instack); mem0(flag); mem0(num); if(C==1){ for(int i=1;i<=n;i++){ for(int j=0;j<G[i].size();j++){ int u=i,v=G[i][j].first,w=G[i][j].second; if(w==1){ addedge(u,v); addedge(v,u); addedge(u+n,v+n); addedge(v+n,u+n); } else{ addedge(u,v+n); addedge(v,u+n); addedge(u+n,v); addedge(v+n,u); } } } } else{ for(int i=1;i<=n;i++){ for(int j=0;j<G[i].size();j++){ int u=i,v=G[i][j].first,w=G[i][j].second; if(w==2){ addedge(u,v); addedge(v,u); addedge(u+n,v+n); addedge(v+n,u+n); } else{ addedge(u,v+n); addedge(v,u+n); addedge(u+n,v); addedge(v+n,u); } } } } Index=scc=top=0; for(int i=1;i<=2*n;i++){ if(!DFN[i]) Tarjan(i,n); } for(int i=1;i<=n;i++){ if(Belong[i]==Belong[i+n]) return ; } int ANS=0; for(int i=1;i<=2*n;i++){ if(flag[i]!=0) continue; if(num[Belong[i]]<=num[Belong[i+n]]){ ANS+=num[Belong[i]]; for(int j=0;j<mp[Belong[i]].size();j++){ int cnt=mp[Belong[i]][j]; if(cnt<=n){ flag[cnt]=1; flag[cnt+n]=2; } else{ flag[cnt]=1; flag[cnt-n]=2; } } } else{ ANS+=num[Belong[i+n]]; for(int j=0;j<mp[Belong[i+n]].size();j++){ int cnt=mp[Belong[i+n]][j]; if(cnt<=n){ flag[cnt]=1; flag[cnt+n]=2; } else{ flag[cnt]=1; flag[cnt-n]=2; } } } } if(ANS<ans){ mem0(vis); ans=ANS; for(int i=1;i<=2*n;i++) if(flag[i]==1) vis[i]=1; } } int main(){ int n,m; scanf("%d%d",&n,&m); int u,v; char s[2]; for(int i=0;i<m;i++){ scanf("%d%d%s",&u,&v,s); if(s[0]=='B')//B���Ϊ1 G[u].push_back(PI{v,1}); else G[u].push_back(PI{v,2}); } ans=INF; solve(n,1); solve(n,2); if(ans==INF) puts("-1"); else{ printf("%d\n",ans); for(int i=1;i<=n;i++) if(vis[i]==1) printf("%d ",i); printf("\n"); } }