POJ 3207 2-sat 判断是否有合法解

来源:互联网 发布:ipad无法下载软件 编辑:程序博客网 时间:2024/05/22 15:47

---------------------------------------------------------------------------------------------------------以下转载自http://cainiao2hao.blogcn.com/articles/poj3207.html

平面上,一个圆,圆的边上按顺时针放着n个点。现在要连m条边,比如a,b,那么a到b可以从圆的内部连接,也可以从圆的外部连接。给你的信息中,每个点最多只会连接的一条边。问能不能连接这m条边,使这些边都不相交。

解题报告:


题意可能刚开始不是很好理解,比如1 5连边,2,6连边,由于点是顺序排列的,一画图就可以发现,这两条边必须一个从圆外面连,一个从内部连,否则就会相交。如果再加入3 7这条边,那么就必须相交了。


这样,就可以转化成标准的2-sta问题:


1:每个边看成2个点:分别表示在内部连接和在外部连接,只能选择一个。计作点i和点i'


2:如果两条边i和j必须一个画在内部,一个画在外部(一个简单判断就可以)


那么连边:


i->j’, 表示i画内部的话,j只能画外部,即j’


j->i’,同理


i’->j,同理


j’->i,同理


然后就是2-sat算法了,tarjan一下,如果有i和i'同属于一个强联通,返回false,否则就成立。

------------------------------------------------------------------------------------------------------------------------

然后是我的代码

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <queue>#define MAXN 1005#define MAXM 2000005#define INF 1000000000using namespace std;int n, m, e, head[MAXN];int dfn[MAXN], low[MAXN], index, instack[MAXN], scc;int top, st[MAXN], fa[MAXN];int x[MAXN], y[MAXN];struct Edge{    int v, next;}edge[MAXM];void init(){    e = index = scc = top = 0;    memset(dfn, 0, sizeof(dfn));    memset(instack, 0, sizeof(instack));    memset(head, -1, sizeof(head));}void insert(int x, int y){    edge[e].v = y;    edge[e].next = head[x];    head[x] = e++;}void tarjan(int u){    int v;    instack[u] = 1;    st[++top] = u;    dfn[u] = low[u] = ++index;    for(int i = head[u]; i != -1; i = edge[i].next)    {        v = edge[i].v;        if(!dfn[v])        {            tarjan(v);            low[u] = min(low[u], low[v]);        }        else if(instack[v]) low[u] = min(low[u], dfn[v]);    }    if(dfn[u] == low[u])    {        scc++;        do        {            v = st[top--];            instack[v] = 0;            fa[v] = scc;        }while(v != u);    }}void build(){    for(int i = 1; i <= m; i++)    {        scanf("%d%d", &x[i], &y[i]);        x[i]++; y[i]++;        if(x[i] > y[i]) swap(x[i], y[i]);    }    for(int i = 1; i <= m; i++)        for(int j = i + 1; j <= m; j++)            if((x[i] <= x[j] && y[i] >= x[j] && y[i] <= y[j]) || (x[i] >= x[j] && x[i] <= y[j] && y[i] >= y[j]))            {                insert(i, j + m);                insert(j, i + m);                insert(i + m, j);                insert(j + m, i);            }    n = 2 * m;}bool check(){    for(int i = 1; i <= m; i++)        if(fa[i] == fa[i + m]) return false;    return true;}void solve(){    for(int i = 1; i <= n; i++)        if(!dfn[i]) tarjan(i);    if(check()) printf("panda is telling the truth...\n");    else printf("the evil panda is lying again\n");}int main(){    scanf("%d%d", &n, &m);    init();    build();    solve();    return 0;}


原创粉丝点击