[poj3207]解题记录

本文介绍了一种使用2-SAT算法解决平面图问题的方法,通过将边转化为点并运用Tarjan算法来判断是否存在冲突的连接方式。文章提供了一个完整的C++实现案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

圆上有n个点(0…n - 1),给出操作u,v,代表在该两点之间连一条边(从圆内部或外部),问是否可以是平面图


分析

我学2-SAT做的第一题
把每条边 ei 拆成两个点,i,i’,i代表从里连,i’代表从外连
然后tarjan后看是否有i和i’在同一强连通分量里


#include <cstdio>
#include <algorithm>
#include <iostream>

using namespace std;

const int N = 1000 + 3;
const int M = 500 + 3;

struct segs
{
    int sta, end;

    bool operator < (const segs &o) const
    {
        return sta < o.sta;
    }
}S[M];

struct edge
{
    int nxt, to;
}E[N * N];
int head[N], tot;

int n, m;
int dfn[N], low[N], bel[N], stk[N], clo, scc_cnt, s_cnt;

inline void add(int a, int b)
{
    E[++ tot].to = b; E[tot].nxt = head[a]; head[a] = tot;
}

void tarjan(int u)
{
    dfn[u] = low[u] = ++ clo;
    stk[++ s_cnt] = u;
    for (int i = head[u]; i; i = E[i].nxt)
    {
        int to = E[i].to;
        if (dfn[to] == 0) 
        {
            tarjan(to);
            low[u] = min(low[u], low[to]);
        }
        else
        {
            low[u] = min(low[u], dfn[to]);
        }
    }
    if (low[u] == dfn[u])
    {
        scc_cnt ++;
        while (stk[s_cnt] != u)
        {
            bel[stk[s_cnt]] = scc_cnt;
            s_cnt --;
        }
        bel[u] = scc_cnt;
        s_cnt --;
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i ++)
    {
        int a, b; scanf("%d%d", &a, &b);
        if (a > b) swap(a, b);
        S[i].sta = a, S[i].end = b;
    }
    sort(S + 1, S + m + 1);
    for (int i = 1; i <= m; i ++)
        for (int j = i + 1; j <= m && S[j].sta < S[i].end; j ++)
            if (S[j].end > S[i].end) 
            {
                add(i, j + m); add(j, i + m);
                add(i + m, j); add(j + m, i);
            }
    for (int i = 1; i <= (m << 1); i ++) 
        if (dfn[i] == 0) tarjan(i);
    for (int i = 1; i <= m; i ++) 
        if (bel[i] == bel[i + m])
        {
            printf("the evil panda is lying again\n");
            return 0;
        }
    printf("panda is telling the truth...\n");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值