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;
}