ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

和平委员会

2019-10-24 20:57:12  阅读:323  来源: 互联网

标签:原图 连通 分量 党派 和平 反图 节点 委员会


https://loj.ac/problem/10097

题目描述

  给出n个党派,每个党派中有2个代表,若两个代表彼此厌恶就都不能成为委员会,求能否成立委员会,若能输出一种可行的方案。

思路

  典型的2-SAT问题,我们用1表示在委员会中,0表示不在委员会中,那么给出的约束条件就是某两个代表的值必须为有一个0,隐藏的约束条件为同党派两个代表中有且只有一个代表的值为1。因此对于两个彼此厌恶的代表a、b,我们假设同党派另两个代表分别为u、v,那么我们可以将u、b连边,v、a连边,这条边的意思是必须,即这条边所连接的点的值必须相同,而建有向边的原因是就是实际意义,不过事实上我们建的是反图,相当于选a必须选v,选b必须选u。接下来我们只要进行缩点,那么在同一个强连通分量中的点必定是同一个值,而如果同个党派的代表在同一个强连通分量里,显然不可能成立。

  接下来考虑如何构造一组解,在原图上构造一组解,我们显然需要按照原图拓扑排序来,因为无入边的节点显然限制更小。具体的构造方法是对于同一党派的两个人a,b,如果a所在的强连通分量拓扑序在b所在强连通分量的前面,那么就取a的值为1。这样做显然是对的,可以从对称性上去分析,事实上缩点后的图也一定是对称的,那么对于两个党派的四个代表A,A',B,B',如果B'是A的后代节点(A到B’有边),那么A’是B的后代节点,显然我们可以推得A’和B'互相厌恶,由于存的是反图,所以我们可以将不选择的标记进行传递,因此如果确定了A选,那么A'的前代节点肯定都不可选,而图的对称性告诉我们A的后代节点和A’的前代节点没有区别,这样就必定能构造出一组解。

  而实际上在反图上跑tarjan并不影响强连通分量的判定,而反图缩点后的DAG,显然在dfs序上是按照原图缩点后拓扑序排好的,不过是倒过来,也就是说得到的强连通分量的节点编号符合反图上的拓扑序,原图上的逆拓扑序,那就可以直接判定同党派两个代表所在强连通分量的大小即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=8800<<1,M=20005<<1;

int nxt[M],to[M],head[N],tot;
void add_edge(int x,int y)
{
    nxt[++tot]=head[x];
    head[x]=tot;
    to[tot]=y;
}

int read()
{
    int res=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+ch-'0';ch=getchar();}
    return res*w;
}

int dfn[N],low[N],st[N],top,idx,co[N],col;
void tarjan(int u)
{
    dfn[u]=low[u]=++idx;
    st[++top]=u;
    for(int i=head[u];i;i=nxt[i])
    {
        int v=to[i];
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!co[v])low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u])
    {
        co[u]=++col;
        while(st[top]!=u)
        {
            co[st[top]]=col;
            --top;
        }
        --top;
    }
}
int main() 
{
    int n,m;
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        int a=read(),b=read(),u,v;
        u=(a&1)?a+1:a-1;
        v=(b&1)?b+1:b-1;
        add_edge(u,b);add_edge(v,a);
    }
    for(int i=1;i<=n*2;i++)
        if(!dfn[i])tarjan(i);
    for(int i=1;i<=n;i++)
        if(co[i*2-1]==co[i*2])
        {
            printf("NIE");
            return 0;
        }
    for(int i=1;i<=n;i++)
        printf("%d\n",co[i*2]>co[i*2-1]?i*2:i*2-1);
    return 0;
}

 

标签:原图,连通,分量,党派,和平,反图,节点,委员会
来源: https://www.cnblogs.com/fangbozhen/p/11734792.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有