POJ 3207 Ikki's Story IV

来源:互联网 发布:mysql主键从1开始 编辑:程序博客网 时间:2024/05/19 22:52

传送门

题意:有一个圆,圆周上有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);#endifmemset(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");elseprintf("the evil panda is lying again\n");return 0;}