您的位置:首页 > 其它

Codeforces Round #347 (Div. 2) D. Graph Coloring(强联通分量缩点+2-SAT)

2016-09-16 18:08 323 查看
题意:

给你n个点m条边,每条边有一种颜色(B或R),每选择一个点可以使与其相连的所有边的颜色翻转,问最少需要选择多少个点,使得所有边的颜色相同,输出操作数以及操作哪些点。

(1 ≤ n,m ≤ 100000)

思路:

我们可以分别对把所有边变成B和R分别考虑。

因为每个点不会操作2次或者更多,因为操作两次相当于不操作,操作三次相当于操作一次。

然后用2-sat强连通模板跑

假设现在要把所有边变成R,现在有u,v两点之间的边为B,

我们用v+n,u+n表示这两个点不翻转,u,v表示这两个点进行翻转

则我们可以建立以下四条边

u->v+n,v+n->u,u+n->v,v->u+n

由于是有向图,所以tarjan不需要判断父亲

</pre><pre name="code" class="cpp">#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define L(i) i<<1
#define R(i) i<<1|1
#define INF  0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-12
#define maxn 200100
#define MOD 1000000007

struct Edge
{
int to,next;
} edge[maxn<<1];

int n,m,ans;
int tot,head[maxn],scc;
int dfn[maxn],low[maxn],time;
int sta[maxn],top,instack[maxn],vis[maxn];
int belong[maxn],num[maxn],flag[maxn];
vector<pair<int,int> > mp[maxn];
vector<int> tmp[maxn];

void init()
{
tot = 0;
memset(head,-1,sizeof(head));
}
void add_edge(int u,int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++time;
sta[++top] = u;
instack[u] = 1;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(!dfn[v])
{
tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(instack[v])
low[u] = min(low[u],dfn[v]);
}
if(dfn[u] == low[u])
{
num[++scc] = 0;
tmp[scc].clear();
while(1)
{
int v = sta[top--];
instack[v] = 0;
belong[v] = scc;
if(v <= n)
num[scc]++;
tmp[scc].push_back(v);
if(v == u)
break;
}
}
}

void solve(int key)
{
init();
for(int u = 1; u <= n; u++)
{
for(int i = 0; i < mp[u].size(); i++)
{
int v = mp[u][i].first;
int c = mp[u][i].second;
if(c == key)
{
add_edge(u,v);
add_edge(u+n,v+n);
}
else
{
add_edge(u,v+n);
add_edge(u+n,v);
}
}
}
top = time = scc = 0;
memset(dfn,0,sizeof(dfn));
memset(instack,0,sizeof(instack));
memset(flag,0,sizeof(flag));
for(int i = 1; i <= 2*n; i++)
if(!dfn[i])
tarjan(i);
for(int i = 1; i <= n; i++)
if(belong[i] == belong[i+n])
return;
int cnt = 0;
for(int i = 1; i <= n; i++)
{
if(flag[i])
continue;
int k;
if(num[belong[i]] <= num[belong[i+n]])
k = i;
else
k = i + n;
cnt += num[belong[k]];
for(int j = 0; j < tmp[belong[k]].size(); j++)
{
int v = tmp[belong[k]][j];
flag[v] = 1;
flag[v<=n?v+n:v-n] = 2;
}
}
if(cnt < ans)
{
memset(vis,0,sizeof(vis));
ans = cnt;
for(int i = 1; i <= n; i++)
if(flag[i] == 1)
vis[i] = 1;
}
}
int main()
{
int t;
while(scanf("%d%d",&n,&m) != EOF)
{
for(int i = 1; i <= n; i++)
mp[i].clear();
for(int i = 0; i < m; i++)
{
int u,v;
char c;
scanf("%d%d %c",&u,&v,&c);
mp[u].push_back(make_pair(v,c=='B'?1:2));
mp[v].push_back(make_pair(u,c=='B'?1:2));
}
ans = INF;
solve(1);
solve(2);
if(ans == INF)
printf("-1\n");
else
{
printf("%d\n",ans);
for(int i = 1; i <= n; i++)
if(vis[i])
printf("%d ",i);
printf("\n");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: