bzoj1997: [Hnoi2010]Planar

2-SAT。

首先有平面图定理 m<=3*n-6,如果不满足这条件肯定不是平面图,直接退出。

然后构成哈密顿回路的边直接忽略。

把哈密顿回路当成一个圆,

如果俩条边交叉(用心去感受),只能一条边在圆内,另一条在圆外。

这个是2-sat的A,B要不同时取,要不同时不取模型。

如果俩个交叉,只能一个在内,一个在外。

和A,B俩者不能同时取有区别,需要注意。

可能存在3个方案(A,B’),(B,A’),(A’,B’)。

连方案都不要,直接tarjan完就过了。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 10000 + 10;
const int maxm = 3000000 + 10;

int g[maxn],v[maxm],next[maxm],eid;
int a[maxn],b[maxn],c[maxn],pos[maxn];
bool t[maxn];
int vis[maxn];
int s[maxn],sp;
int dfn[maxn],low[maxn],vid;
int color[maxn],cid;
int T,n,m;
 
void addedge(int a,int b) {
    v[eid]=b; next[eid]=g[a]; g[a]=eid++;
    v[eid]=a; next[eid]=g[b]; g[b]=eid++;
}

bool build() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) scanf("%d%d",&a[i],&b[i]);
    for(int i=1;i<=n;i++) {
        scanf("%d",&c[i]);
        pos[c[i]]=i;
    }
    if(m>3*n-6) {
        printf("NO\n");
        return false;
    }
    memset(g,-1,sizeof(g)); eid=0;
    memset(t,0,sizeof(t));
    for(int i=1;i<=m;i++) {
        a[i]=pos[a[i]];
        b[i]=pos[b[i]];
        if(a[i]>b[i]) swap(a[i],b[i]);
    }
    for(int i=1;i<=m;i++) 
        if(a[i]+1==b[i] || (a[i]==1&&b[i]==n)) t[i]=true;    
    for(int i=1;i<=m;i++) if(!t[i]) {
        for(int j=1;j<=m;j++) if(i!=j && !t[j])
            if(a[i]<a[j] && a[j]<b[i] && b[i]<b[j]) {
                addedge((i<<1),(j<<1)|1);
                addedge((i<<1)|1,(j<<1));
            }
    }
    return true;
}

void tarjan(int u) {
    dfn[u]=low[u]=++vid;
    vis[u]=1; s[++sp]=u;
    
    for(int i=g[u];~i;i=next[i]) {
        if(!vis[v[i]]) {
            tarjan(v[i]);
            low[u]=min(low[u],low[v[i]]);    
        }
        else if(vis[v[i]]==1)
            low[u]=min(low[u],dfn[v[i]]);
    }
    
    if(dfn[u]==low[u]) {
        ++cid;
        do {
            color[s[sp]]=cid;
            vis[s[sp]]=2;
        }while(s[sp--]!=u);
    }
}

void solve() {
    memset(vis,0,sizeof(vis));
    vid=cid=sp=0;
    for(int i=1;i<=m;i++) if(!t[i]) {
        if(!vis[i<<1]) tarjan(i<<1);
        if(!vis[i<<1|1]) tarjan((i<<1|1));    
    }
    for(int i=1;i<=m;i++) if(!t[i]&&color[i<<1]==color[i<<1|1]) {
        printf("NO\n");
        return;
    }
    printf("YES\n");    
}

int main() {
    scanf("%d",&T);
    while(T--) if(build()) solve();        
    return 0;
}
posted @ 2016-07-08 12:30  invoid  阅读(562)  评论(0编辑  收藏  举报