题意:
平面上有一个圆,圆的边上按顺时针放着n个点
现在要连m条边(a,b),a到b可以从圆的内部连接,也可以从圆的外部连接
信息中,每个点最多只会连接的一条边,问能不能连接这m条边,使这些边都不相交
分析:
经典的2_SAT问题
建图:对于一条边i,在圆内记为i,在圆外记为i’。
设边
i
i
连接点,边
j
j
连接点
i
i
与在圆内是否相交就是线段
AB
A
B
与线段
CD
C
D
是否相交
可以证明,如果
i
i
与在圆内不能共存,则在圆外也一定不能共存,即:
i
i
在圆内,则一定在圆外,建边
i−>j′
i
−
>
j
′
i
i
在圆外,则一定在圆内,建边
i′−>j
i
′
−
>
j
j
j
在圆内,则一定在圆外,建边
j−>i′
j
−
>
i
′
j
j
在圆外,则一定在圆内,建边
j′−>i
j
′
−
>
i
因为只是判定性问题,所以一遍tarjan缩点判断冲突的点是不是在一个scc中即可
摘录一点dada的言论,方便理解:
不要急,请先达成一点共识:
1. 如果很多节点已经处在一个强连通分量内了,也就是它们两两均可互达了,那么意味着选择了其中的一个,整个强连通分量都将被选择,如果不选择其中的一个,那么整个强连通分量内都不能够被选择
2. 如果一个集合的两个元素处在了同一个强连通分量内,也就是说要么都不选,要么都被选,那么题目要求的选出一个就一定无法成立了
3. 题中不管给出哪两个不能同时选,都不能改变我们连的边都是对称的这一事实,只要A到B有边,那么B的对立节点到A的对立节点就有边
4. 边的对称意味着图的对称,原图的对称意味着哪怕用强连通分量缩点后的图一样对称,所以对立节点的概念也可以应用在强连通分量上
5. 为了叙述方便,以下简称强连通分量为块,注意:真正的块指的是点双连通分量,这里只是一种形象化的表述,是不规则的!
tip
2_SAT第一题,就当是临阵磨枪,临时抱佛脚吧
把空间算好了
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=2010;
struct node{
int x,y,nxt;
};
node way[500010];
int st[N],tot=0,n,m,x[N],y[N];
int jiao(int a,int b) {
if (x[a]<=x[b]&&x[b]<=y[a]&&y[b]>=y[a]) return 1;
if (x[b]<=x[a]&&x[a]<=y[b]&&y[a]>=y[b]) return 1;
return 0;
}
void add(int u,int w) {
tot++;way[tot].x=u;way[tot].y=w;way[tot].nxt=st[u];st[u]=tot;
}
int dfn[N],low[N],clo=0,cnt=0,belong[N],S[N],top=0;
bool vis[N];
void tarjan(int now) {
S[++top]=now;
dfn[now]=low[now]=++clo;
vis[now]=1;
for (int i=st[now];i;i=way[i].nxt)
if (!dfn[way[i].y]) {
tarjan(way[i].y);
low[now]=min(low[now],low[way[i].y]);
}
else if (vis[way[i].y])
low[now]=min(low[now],dfn[way[i].y]);
if (low[now]==dfn[now]) {
cnt++;
int x=0;
while (x!=now) {
x=S[top--];
vis[x]=0;
belong[x]=cnt;
}
}
}
bool solve() {
for (int i=1;i<=m;i++)
if (!dfn[i])
tarjan(i);
for (int i=1;i<=m;i++)
if (belong[i]==belong[i+m]) return 0;
return 1;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++) {
scanf("%d%d",&x[i],&y[i]);
if (x[i]>y[i]) swap(x[i],y[i]);
}
for (int i=1;i<=m;i++)
for (int j=i+1;j<=m;j++)
if (jiao(i,j)) {
add(i,j+m); add(j,i+m);
add(j+m,i); add(i+m,j);
}
if (solve()) printf("panda is telling the truth...\n");
else printf("the evil panda is lying again\n");
return 0;
}