题意:有一个圆,圆周上有n个顺序的点,然后有m组边,这些边的两个点必须连起来,圆有两个面,你可以在正面连接他们,也可以在反面连接他们。问是否可以使得这m条线不相交。
解法:因为这些点是按照顺序排序的,在同一个面的情况下,有两对线分别是1 5,2 6,那么就会发现他们肯定是相交的,其实就是一个规律,a[i] < a[j] && a[j] < b[i] && b[i] < b[j].这样肯定是相交的,所以我们遇到这种情况只能将他们放到两面上去。从而转化为2-SAT问题。判断的话就是如果有一面的i和另外一面的i在同一个强联通分量里面那么就说明情况不存在。
2-SAT连的是必须共存的点。对于本题来说,在build中,如果满足相交的条件,那么就是选取了i只能选取j^1,选取了j只能选取i^1.由于有正反两面的性质。所以我们要拆点,每个点都应该对应两个点。
代码如下:
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<utility>
#include<stack>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<set>
#include<map>
using namespace std;
const int maxn = 1010 * 2;
const int maxm = 2e6 + 5;
stack <int> sta;
int dfn[maxn], low[maxn], key[maxn], tot = 0, num = 1;
int belong[maxn];
int n, m;
int a[maxn], b[maxn];
int to[maxm], nx[maxm], head[maxn], ppp;
void add_edge(int u, int v) {
to[ppp] = v, nx[ppp] = head[u], head[u] = ppp++;
}
void tarjan(int u) {
sta.push(u);
dfn[u] = low[u] = tot++;
key[u] = 1;
for(int i = head[u]; ~i; i = nx[i]) {
int v = to[i];
if(dfn[v] == -1) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if(key[v] == 1) {
low[u] = min(low[u], dfn[v]);
}
}
if(dfn[u] == low[u]) {
while(1) {
int v = sta.top();
sta.pop();
belong[v] = num;
key[v] = 2;
if(v == u)
break;
}
num++;
}
}
void build() {
for(int i = 1; i <= m; i++) {
for(int j = i + 1; j <= m; j++) {
if((a[i] < a[j] && a[j] < b[i] && b[i] < b[j]) ||
(a[j] < a[i] && a[i] < b[j] && b[j] < b[i])) {
add_edge(2 * i - 1, 2 * j);
add_edge(2 * j, 2 * i - 1);
add_edge(2 * j - 1, 2 * i);
add_edge(2 * i, 2 * j - 1);
}
}
}
}
bool Check() {
for(int i = 1; i <= m; i++)
if(belong[2 * i] == belong[2 * i - 1])
return 0;
return 1;
}
int main() {
#ifndef ONLINE_JUDGE
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif
memset(head, -1, sizeof(head));
memset(dfn, -1, sizeof(dfn));
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i++) {
scanf("%d%d", &a[i], &b[i]);
if(a[i] > b[i])
swap(a[i], b[i]);
}
build();
// cout << "hello" << '\n';
for(int i = 1; i <= 2 * m; i++) {
if(dfn[i] == -1)
tarjan(i);
}
if(Check())
printf("panda is telling the truth...\n");
else
printf("the evil panda is lying again\n");
return 0;
}