Codeforces Round #747 (Div. 2) D题

D. The Number of Imposters

题目链接: link.

题意:

N N N个人,每个人都有可能是好人或者坏人,现在又 M M M句话,每句话都是都是 i , j , s t r i,j,str i,j,str的形式就是指第 i i i个人说 j j j号是好人或者坏人。好人说真话,坏人说假话,现在问,在有这些逻辑关系下,坏人最多有多少个。

思路:

这个题类似于 2 − s a t 2-sat 2sat问题,对于一个连通块内,如果你确认一个人的好坏身份,那么此时整个连通块的好坏身份都将通过逻辑关系推断出来,也就是说,对于每个连通块都可以给其中一个点赋值(附上好坏关系),然后通过染色法,来求出整个连通块的好坏关系,由于好坏是对称的,所以取最大值,就是坏人的最大值。
u 说 v 是 好 的 u说v是好的 uv,那么u和v就是同种关系,同好同坏
u 说 v 是 坏 的 u说v是坏的 uv,那么就是相反关系
通过染色法,对于每个连通块中的一个点赋值,并跑 d f s dfs dfs来染色,如果出现矛盾即如果无穷小,最后输出-1即可

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int h[N],e[2*N],w[2*N],ne[2*N],idx;
int color[N];
int n,m;
char str[20];
int ans1,ans2;
int res;
void clear_graph() {
    memset(h,-1,(n+1)*4);
    memset(color,-1,(n+1)*4);
    idx=0;
}
void add_edge(int a,int b,int c) {
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

void dfs(int u,int c) {
    color[u]=c;
    if(c==0) ans1++;
    else ans2++;
    for(int i=h[u];~i;i=ne[i]) {
        int j=e[i];
        if(color[j]==-1) {
            dfs(j,c^w[i]);
        }
        else {
            if((color[j]^color[u])!=w[i]) {
                res=-99999999;
            }
        }
    }
}
int main() {
    int T;
    cin>>T;
    while(T--) {
        res=0;
        scanf("%d%d",&n,&m);
        clear_graph();
        for(int i=1,u,v;i<=m;i++) {
            scanf("%d%d",&u,&v);
            scanf("%s",str);
            if(str[0]=='i') {
                add_edge(u,v,1);
                add_edge(v,u,1);
            }
            else {
                add_edge(u,v,0);
                add_edge(v,u,0);
            }
        }

        for(int i=1;i<=n;i++) {
            if(color[i]==-1) {
                ans1=0,ans2=0;
                dfs(i,0);
                res+=max(ans1,ans2);
            }
        }
        if(res<0) printf("-1\n");
        else printf("%d\n",res);
    }
    return 0;
}

To be continued
如果你有任何建议或者批评和补充,请留言指出,不胜感激

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值