bzoj 1997 Planar [并查集] [二分图判定] [2-SAT]

来源:互联网 发布:南京麦芽金服数据 编辑:程序博客网 时间:2024/06/04 19:03

1997: [Hnoi2010]Planar

Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 1509 Solved: 585

Description
这里写图片描述
Input
这里写图片描述
Output
这里写图片描述
Sample Input
2
6 9
1 4
1 5
1 6
2 4
2 5
2 6
3 4
3 5
3 6
1 4 2 5 3 6
5 5
1 2
2 3
3 4
4 5
5 1
1 2 3 4 5

Sample Output
NO
YES

Source
Day1


三种做法,并查集,二分图判定,2-SAT
前两种就是上一道题的check,但是注意要剪枝,m<=3n-6时才有可能成为平面图。


2-SAT解法:

这道题把所有边拆成两个,分别代表在里面和在外面,然后又里面和外面取且一定取一个,那么连上四条边即可。。
又因为这道题只用判断可行性,那么就只用缩点之后判断是否有冲突即可,如果要输出方案,那么就需要按照拓扑序的反序进行点的确定,然后依次标记可选的点,传递不能选的标记,然后该图的染色就是2-SAT问题的解。
另外要注意提前break的时候要保证读完该组数据,不然RE…

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<vector>#include<queue>#include<stack>#include<map>#include<set>#include<string>#include<iomanip>#include<ctime>#include<climits>#include<cctype>#include<algorithm>#ifdef WIN32#define AUTO "%I64d"#else#define AUTO "%lld"#endifusing namespace std;#define smax(x,tmp) x=max((x),(tmp))#define smin(x,tmp) x=min((x),(tmp))#define maxx(x1,x2,x3) max(max(x1,x2),x3)#define minn(x1,x2,x3) min(min(x1,x2),x3)const int INF=0x3f3f3f3f;const int maxnode = 205;const int maxn = 605;const int maxm = 10005;struct Edge{    int to,next;}edge[maxn*maxn<<2]; // 4 edges per conditionint head[maxn<<1]; // dividedint maxedge;inline void addedge(int u,int v){    edge[++maxedge] = (Edge) { v,head[u] };    head[u] = maxedge;}struct Road{    int u,v;}road[maxn],save[maxm];bool g[maxnode][maxnode];int a[maxnode],order[maxnode];int n,m,tmp;void init(){    memset(g,0,sizeof(g));    memset(head,-1,sizeof(head));    maxedge = -1;    m=0;    for(int i=1;i<=tmp;i++) scanf("%d%d",&save[i].u,&save[i].v);    for(int i=1;i<=n;i++) scanf("%d",a+i),order[a[i]]=i;    if(tmp>n*3-6) return; // spacial judge after scanning!!    for(int i=1;i<n;i++) g[a[i]][a[i+1]] = g[a[i+1]][a[i]] = true;    g[a[1]][a[n]] = g[a[n]][a[1]] = true;    for(int i=1;i<=tmp;i++) if(!g[save[i].u][save[i].v]) road[++m]=save[i];}inline bool cross(int i,int j) // cases of including node n,1 is considered another way{    int x1=order[road[i].u],y1=order[road[i].v];    int x2=order[road[j].u],y2=order[road[j].v];    if(x1>y1) swap(x1,y1);    if(x2>y2) swap(x2,y2);    return (x1<x2 && x2<y1 && y1<y2) || (x2<x1 && x1<y2 && y2<y1);}int dfn[maxn<<1],sccno[maxn<<1];bool insta[maxn<<1];int scc_cnt,dfs_clock;stack <int> sta;int dfs(int u){    int lowu=dfn[u]=++dfs_clock;    sta.push(u); insta[u]=true;    for(int i=head[u];~i;i=edge[i].next)    {        int v = edge[i].to;        if(!dfn[v])        {            int lowv = dfs(v);            smin(lowu,lowv);        }        else if(insta[v]) smin(lowu,dfn[v]);    }    if(lowu>=dfn[u])    {        scc_cnt++;        int t;        do        {            t=sta.top(); sta.pop(); insta[t]=false;            sccno[t]=scc_cnt; // if needed to print , note the nodes of SCC        }while(t^u);    }    return lowu;}void Tarjan(){    memset(dfn,0,sizeof(dfn));    memset(sccno,0,sizeof(sccno));    dfs_clock = scc_cnt = 0;    for(int i=1;i<=m;i++)    {        if(!dfn[i]) dfs(i);        if(!dfn[i+m]) dfs(i+m);    }}inline bool check(){    for(int i=1;i<=m;i++)        if(sccno[i] == sccno[i+m]) return false;    return true;}int main(){    #ifndef ONLINE_JUDGE    freopen("planar.in","r",stdin);    freopen("planar.out","w",stdout);    #endif    int cas;    scanf("%d",&cas);    while(cas--)    {        scanf("%d%d",&n,&tmp);        init();        if(tmp>n*3-6) // judge after scanning all data!!        {            printf("NO\n");            continue;        }        for(int i=1;i<m;i++)            for(int j=i+1;j<=m;j++)                if(cross(i,j))                {                    addedge(i,j+m);                    addedge(j,i+m);                    addedge(i+m,j);                    addedge(j+m,i);                }        Tarjan();        if(check()) printf("YES\n");        else printf("NO\n");    }    return 0;}
0 0
原创粉丝点击