UOJ 210 [UER #6]寻找罪犯

来源:互联网 发布:公司美工属于什么部门 编辑:程序博客网 时间:2024/06/03 17:40

2-SAT

首先2-SAT的tarjan做适用于一类如果A->B,则一定有B’->A’的对称的图。

一个强联通分量里的所有点,要么一起选要么一起不选,那就缩起来。

一个重要的结论是如果一个强联通分量里同时有A和A’,则此图无解,否则一定有解。

无解的情况显然正确。

有解的情况考虑构造。每次随便从点集里抓一个点A出来,选中A的所有可达点,删去所有可达A’的点。显然这是可以做到的。

那这样会不会把图弄成无解?考虑如果一个B->A,那么选了A及其可达点,那B选不选是不影响的。对于不可达A的显然也不影响,因此可以这样构造。

一个特例是存在A->A’的边,那这样选A就挂了,因此逆拓扑序 来构造才是更一般的做法。

#include<cstdio>#include<vector>#include<algorithm>#define N 600005using namespace std;namespace runzhe2000{    int read()    {        int r = 0; char c = get    }     vector<int> vec[N];    int n, nn, m, tmp, ecnt, last[N], dfn[N], low[N], timer, sta[N], stacnt, bcnt, bel[N], insta[N];    struct edge{int next, to;}e[N*10];    struct state{int a, b, type;}st[N];    void addedge(int a, int b)    {        e[++ecnt] = (edge){last[a], b};        last[a] = ecnt;    }    void tarjan(int x)    {        dfn[x] = low[x] = ++timer; sta[++stacnt] = x; insta[x] = 1;        for(int i = last[x]; i; i = e[i].next)        {            int y = e[i].to;             if(!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]);            else if(insta[y])low[x] = min(low[x], dfn[y]);        }        if(low[x] == dfn[x])        {            bel[x] = ++bcnt; insta[x] = 0;            for(; sta[stacnt] != x; stacnt--)                bel[sta[stacnt]] = bcnt, insta[sta[stacnt]] = 0;            stacnt--;        }    }    void main()    {        scanf("%d%d",&n,&m); nn = n+n; tmp = n+n+m+m+1;        for(int i = 1; i <= m; i++)        {            scanf("%d%d%d",&st[i].a,&st[i].b,&st[i].type);            addedge(st[i].a, i+nn); addedge(i+nn+m, st[i].a+n);            addedge(i+nn, st[i].b+(st[i].type?0:n));            addedge(st[i].b+(st[i].type?n:0), i+nn+m);            vec[st[i].a].push_back(i);        }        for(int i = 1; i <= n; i++)        {            for(int j = 0, siz = vec[i].size(); j < siz; j++)             {                //tmp+j pre   tmp+siz+j suf                addedge(tmp+j, vec[i][j]+nn);                addedge(tmp+siz+j, vec[i][j]+nn);                j          ? addedge(tmp+j, tmp+j-1)        , addedge(vec[i][j]+nn+m, tmp+j-1)     : void();                j != siz-1 ? addedge(tmp+siz+j, tmp+siz+j+1), addedge(vec[i][j]+nn+m, tmp+siz+j+1) : void();            }            tmp += (vec[i].size()<<1);        }        for(int i = 1; i <= tmp; i++) if(!dfn[i]) tarjan(i); int cnt = 0;        for(int i = 1; i <= n; i++)         {            if(bel[i] == bel[i+n]) return (void)puts("Impossible");             cnt += bel[i] > bel[i+n];        }        for(int i = 1; i <= m; i++) if(bel[i+nn] == bel[i+nn+m]) return (void)puts("Impossible");        printf("%d\n",cnt);        for(int i = 1; i <= n; i++) if(bel[i] > bel[i+n]) printf("%d ",i);    }}int main(){    runzhe2000::main();}
0 0
原创粉丝点击