【算法练习】POJ - 3207 Ikki's Story IV - Panda's Trick (2-SAT)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pengwill97/article/details/82021811

题意

给出一个 n 的点的环, m 条线,每条线连接环上的点。线可以从环内部连接也可以从环外部连接。求能否使得这 m 条线不相交。

题解

首先要知道一个引理:如果两条线从环都从内部连接相交的话,那么他们从外部连接一样会相交
有了这个引理,为了让两条原本相交的线 l a l b 变得不相交,就必须然们一条从内部连接,一条从外部连接。
设布尔变量 a b 表示直线 l a l b 的连接情况,当其取1的时候表示从内部连接,取0表示从外部连接。
根据上面的推理,就有 a b = 1 , a b = 0 的逻辑表示。
通俗来讲,就是两条线一条从外部连接,一条从内部连接。
再推理,就可以得到:

  1. 如果 l a 从外部,那么 l b 一定从内部,反之也成立。
  2. 如果 l b 从外部,那么 l a 一定从内部,反之也成立。

建立2-sta的模型,用4条有向边来表示上面的逻辑推理。
之后利用tarjan算法缩点,因为题目只需要判断是否有解,所以只需要判断原变量和反变量是否在一个强连通分量中,若在的话,问题无解,反之一定有解。

最后一点,如何判断两条线是否相交呢?这个问题其实画画就出来了。
l a x l a y l b x l b y 分别表示两条线的两个端点编号,并且有 l i x l i y
如果有下面几种情况之一,即可判断两条直线相交:

  1. l a x l b x l a y l b x l a y l b y
  2. l b x l a x l b y l a x l b y l a y
  3. l a x l b x l a x l b y l a y l b y
  4. l b x l a x l b x l a y l b y l a y

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e5 + 7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
int n, m, cnt;
typedef pair<int , int > pii;
pii line[nmax];
struct edge {
    int to, nxt;
};
struct graph {
    int tot, head[nmax];
    edge e[(int)1e6 + 7];
    void init() {
        tot = 0;
        memset(head, -1, sizeof head);
    }
    void add_edge(int u, int v) {
        e[tot].to = v;
        e[tot].nxt = head[u];
        head[u] = tot ++;
    }
}g;
inline bool checkcross(pii a, pii b) {
    if(a.first <= b.first && a.second >= b.first && a.second <= b.second)
        return true;
    else if(b.first <= a.first && b.second >= a.first && b.second <= a.second)
        return true;
    else if(a.first >= b.first && a.first <= b.second && a.second >= b.second)
        return true;
    else if(b.first >= a.first && b.first <= a.second && b.second >= a.second)
        return true;
    else
        return false;
}
int dfn[nmax], low[nmax], dfs_clock, color[nmax], scc;
int ss[nmax], st;
bool instack[nmax];
void tarjan(int u, const graph & g) {
    dfn[u] = low[u] = ++dfs_clock;
    ss[st++] = u;
    instack[u] = true;
    for(int i = g.head[u]; i != -1; i = g.e[i].nxt) {
        int v = g.e[i].to;
        if(!dfn[v]) {
            tarjan(v, g);
            low[u] = min(low[u], low[v]);
        } else if (instack[v]) {
            low[u] = min(low[u], dfn[v]);
        }
    }
    if(dfn[u] == low[u]) {
        scc++;
        int tmp;
        while(true) {
            tmp = ss[--st];
            color[tmp] = scc;
            instack[tmp] = false;
            if(tmp == u)
                break;
        }
    }
}
bool check() {
    for(int i = 1; i <= m; ++i) {
        if(color[i] == color[i+m])
            return false;
    }
    return true;
}
void init() {
    memset(dfn, 0, sizeof dfn);
    memset(low, 0, sizeof low);
    memset(color, 0, sizeof color);
//    memset(instack, 0, sizeof instack);
    scc = dfs_clock = st;
    g.init();
}
int main(){
    while(scanf("%d %d", &n, &m) != EOF) {
        init();
        int a, b;
        for(int i = 1; i <= m; ++i) {
            scanf("%d %d", &a, &b);
            if(a < b) {
                line[i].first = a;
                line[i].second = b;
            } else {
                line[i].first = b;
                line[i].second = a;
            }
        }

        for(int i = 1; i <= m ;++i) {
            for(int j = i + 1; j <= m; ++j) {
                if(checkcross(line[i], line[j])) {
                    g.add_edge(i, j + m);
                    g.add_edge(i + m, j);
                    g.add_edge(j, i + m);
                    g.add_edge(j + m, i);
                }
            }
        }
        for(int i = 1; i <= 2 * m; ++i) {
            if(!dfn[i])
                tarjan(i, g);
        }
        if(check()) {
            printf("panda is telling the truth...\n");
        } else {
            printf("the evil panda is lying again\n");
        }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/pengwill97/article/details/82021811