POJ - 3207 Ikki‘s Story IV - Panda‘s Trick
Posted 吃花椒的妙酱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ - 3207 Ikki‘s Story IV - Panda‘s Trick相关的知识,希望对你有一定的参考价值。
传送门
题目大意:一个圆上n个点,按顺时针排布,对定m组连线,连线可以在圆内或者圆外,问是否存在方法,使得任意两条线段不相交。
画一下图可以发现,当a < b < c < d时,两条线在圆内或者圆外相交
我们研究的对象是每条线段,线段无非在圆内或圆外,转化成2sat问题。
我们将所有线段编号,枚举判断两两线段是否满足相交的条件,若满足,就去建图,举个例子。
如上图,若ac在圆内,则bd必在圆外,若ac在圆外,则bd必在圆内,这样对于满足相交的两个线段就可以去连两条边。
设两条线段编号为x,y共n条,x,y表示线段在圆内,x+n,y+n表示线段在圆外,如果两者满足相交条件,则有有向边,x->y+n,x+n->y,y->x+n,y+n->x
后面就是套路了,看一下圆内圆外的同一条线段col[i] == col[i+n]?是否在同一强连通块里,是的话说明矛盾,反之成立
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
using namespace std;
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define pb push_back
#define IOS ios::sync_with_stdio(false)
#define int long long
#define inf 0x3f3f3f3f
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
#define ls p<<1
#define rs p<<1|1
#define endl "\\n"
#define sf scanf
typedef long long ll;
const int N = 1000 + 10;//500条边,
int n, m;
int sta[N],low[N],dfn[N],col[N],tot,top,ti;
bool pd[N];
vector <int> G[N];
void tarjan(int x)
{
sta[++top] = x;
pd[x] = 1;
dfn[x] = low[x] = ++ti;
for (int i = 0; i < G[x].size(); i++)
{
int y = G[x][i];
if (!dfn[y])
{
tarjan(y);
low[x] = min(low[x], low[y]);
}
else if (pd[y])
{
low[x] = min(low[x], low[y]);
}
}
if (dfn[x] == low[x])
{
tot++;
while (sta[top + 1] != x)
{
col[sta[top]] = tot;
pd[sta[top--]] = 0;
}
}
}
struct ty
{
int x, y;
}edge[N];
bool min4(int a, int b, int c, int d)
{
if (a < b && b < c && c < d) return true;
return false;
}
bool check(int i, int j)//相交
{
int a = edge[i].x;
int b = edge[i].y;
int c = edge[j].x;
int d = edge[j].y;
if (min4(a, c, b, d)) return true;
if (min4(c, a, d, b)) return true;
return false;
}
signed main()
{
///!!!
//freopen("data.txt","r",stdin);
//!!!
IOS;
cin >> n >> m;
_for(i, 1, m)
{
int x, y; cin >> x >> y;
if (x > y) swap(x, y);
edge[i] = { x,y };
}
_for(i, 1, m)
{
_for(j, i + 1, m)
{
//如果相交就建图
//边的编号+n表示连在圆外
if (check(i, j))
{
G[i].push_back(j + m);
G[j].push_back(i + m);
G[i + m].pb(j);
G[j + m].pb(i);
}
}
}
_for(i, 1, 2 * m) if (!dfn[i]) tarjan(i);
_for(i, 1, m)
{
//如果一条边在一个连通块里->同时出现在圆外和圆内
if (col[i] == col[i + m])
{
cout << "the evil panda is lying again";
return 0;
}
}
cout << "panda is telling the truth...";
return 0;
}
以上是关于POJ - 3207 Ikki‘s Story IV - Panda‘s Trick的主要内容,如果未能解决你的问题,请参考以下文章
poj3207 Ikki's Story IV - Panda's Trick
poj 3207 Ikki's Story IV - Panda's Trick 2-SAT
[2-SAT] poj 3207 Ikki's Story IV - Panda's Trick
POJ 3207 Ikki's Story IV - Panda's Trick