题意
圆上有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;
}