# bzoj2215: [Poi2011]Conspiracy 2-sat

bzoj2215: [Poi2011]Conspiracy 2-sat

链接

https://www.lydsy.com/JudgeOnline/problem.php?id=2215

思路

一个点的属性为去当同谋者和后勤两种
求出一种方案来很简单(只需要用简单的2-sat)
我们发现一条特别重要的性质:
一个方案只会由已经求出的其他任意一种方案改变一方的一个人得来
(基本看出来就稳了)
因为两个人不能同时过去(显然)
那么我们先求出一种方案
然后统计ok[i],表示i到对面冲突的点的个数
显然只有几种情况(大力分情况讨论)
①.一个间谍去后勤
②.一个后勤区去间谍
就是ok==0的个数(注意双方都不能为0个人)
③.间谍和后勤互换(容易发现交换的两个人一定一个是0,一个是1)
好了。

错误

tarjan求方案的方向居然写反了、、、
还有mp的i+n没减n

代码

#include <iostream>
#include <cstdio>
#include <vector>
#define iter vector<int>::iterator
const int N=5007;
using namespace std;
int read() {
    int x=0,f=1;char s=getchar();
    for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
    return x*f;
}
int n,ok[N<<1],dsr;
bool mp[N][N];
vector<int> ans[2];
struct node {
    int v,nxt;
}e[N*N];
int head[N<<1],tot;
void add(int u,int v) {
    e[++tot].v=v;
    e[tot].nxt=head[u];
    head[u]=tot;
}
int dfn[N<<1],low[N<<1],stak[N<<1],top,cnt,belong[N<<1],vis[N<<1];
void tarjan(int u) {
    dfn[u]=low[u]=++cnt;
    vis[u]=1;
    stak[++top]=u;
    for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(!dfn[v]) {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        } else if(vis[v]) {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u]) {
        belong[0]++;
        while(stak[top]!=u) {
            vis[stak[top]]=0;
            belong[stak[top]]=belong[0];
            top--;
        } top--;
        vis[u]=0;
        belong[u]=belong[0];
    }
}
int main() {
    n=read();
    for(int i=1;i<=n;++i) {
        int k=read();
        for(int j=1;j<=k;++j) mp[i][read()]=1;
    }
    for(int i=1;i<=n;++i) {
        for(int j=1;j<i;++j) {
            if(mp[i][j]) {
                add(i,j+n),add(j,i+n);
            } else {
                add(i+n,j),add(j+n,i);
            }
        }
    }
    for(int i=1;i<=n+n;++i)
        if(!dfn[i])
            tarjan(i);
    for(int i=1;i<=n;++i) {
        if(belong[i]==belong[i+n]) {
            puts("0");
            return 0;
        }
    }
    for(int i=1;i<=n;++i) {
        if(belong[i] < belong[i+n]) ans[0].push_back(i);
        else ans[1].push_back(i+n);
    }
    if(ans[0].size()&&ans[1].size()) dsr++;
    for(iter i=ans[0].begin();i!=ans[0].end();++i) {
        for(iter j=ans[1].begin();j!=ans[1].end();++j) {
            if(!mp[*i][*j-n]) ok[*i]++;     
        }
    }
    for(iter i=ans[1].begin();i!=ans[1].end();++i) {
        for(iter j=ans[0].begin();j!=ans[0].end();++j) {
            if(mp[*i-n][*j]) ok[*i]++;
        }
    }
    int siz_0[2]={};
    for(int k=0;k<=1;++k)
        for(iter i=ans[k].begin();i!=ans[k].end();++i)
            if(!ok[*i]) siz_0[k]++;
    if(ans[0].size()>1) dsr+=siz_0[0];
    if(ans[1].size()>1) dsr+=siz_0[1];
    for(iter i=ans[0].begin();i!=ans[0].end();++i) {
        if(ok[*i]==1) {
            for(iter j=ans[1].begin();j!=ans[1].end();++j) {
                if(!mp[*i][*j-n]&&!ok[*j]) dsr++;
            }
        }
    }
    for(iter i=ans[1].begin();i!=ans[1].end();++i) {
        if(ok[*i]==1) {
            for(iter j=ans[0].begin();j!=ans[0].end();++j) {
                if(mp[*i-n][*j]&&!ok[*j]) dsr++;
            }
        }
    }
    printf("%d\n",dsr);
    return 0;
}
全部评论

相关推荐

11-15 19:28
已编辑
蚌埠坦克学院 硬件开发
点赞 评论 收藏
分享
找不到工作死了算了:没事的,雨英,hr肯主动告知结果已经超越大部分hr了
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务