您的位置:首页 > 其它

bzoj1997[Hnoi2010]Planar 2-SAT

2017-08-02 11:14 351 查看
跟poj3207的思想差不多,就是圆上的两条边如果相交,一定得有一条在圆外,然后就是2-SAT的模型了。

要注意一下直接上2-SAT会爆炸,加一个剪枝,就是平面图要求边数<=3n-6

好像还可以用并查集做。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e5+5;
const int inf=1e9;
int n,m,ind,top,cnt,scc;
int x
,y
;
int c
,pos
;
int head
,next[N*10],go[N*10],dfn
,low
,bl
,q
;
bool vis
;
int tot;
inline void add(int x,int y)
{
go[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
inline void tarjan(int x)
{
vis[x]=1,q[++top]=x;
low[x]=dfn[x]=++ind;
for(int i=head[x];i;i=next[i])
{
int v=go[i];
if (!dfn[v])tarjan(v),low[x]=min(low[x],low[v]);
else if (vis[v])low[x]=min(low[x],dfn[v]);
}
if (low[x]==dfn[x])
{
scc++;
int t=-1;
while (t!=x)
{
t=q[top--];
vis[t]=0;
bl[t]=scc;
}
}
}
inline bool pd()
{
fo(i,1,m)
if (bl[2*i]==bl[2*i-1])return 0;
return 1;
}
int main()
{
int cas;
scanf("%d",&cas);
while (cas--)
{
scanf("%d%d",&n,&m);
fo(i,1,m)scanf("%d%d",&x[i],&y[i]);
tot=0,memset(head,0,sizeof(head));
scc=ind=0;
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
fo(i,1,n)scanf("%d",&c[i]),pos[c[i]]=i;
if (m>3*n-6)
{
puts("NO");
continue;
}
top=0;
fo(i,1,m)
{
y[i]=pos[y[i]],x[i]=pos[x[i]];
if (x[i]>y[i])swap(x[i],y[i]);
if (y[i]-x[i]==1||(y[i]==n&&x[i]==1))continue;
x[++top]=x[i],y[top]=y[i];
}
m=top;
fo(i,1,m)
fo(j,i+1,m)
if ((x[i]<x[j]&&x[j]<y[i]&&y[i]<y[j])||(x[j]<x[i]&&x[i]<y[j]&&y[j]<y[i]))
{
add(2*i-1,2*j);
add(2*i,2*j-1);
add(2*j-1,2*i);
add(2*j,2*i-1);
}
top=0;
fo(i,1,2*m)if (!dfn[i])tarjan(i);
if (pd())puts("YES");
else printf("NO\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: