• [bzoj1997][Hnoi2010]Planar(2-sat||括号序列)


      开始填连通分量的大坑了= =

      然后平面图有个性质m<=3*n-6.....

      由平面图的欧拉定理n-m+r=2(r为平面图的面的个数),在极大平面图的情况可以代入得到m=3*n-6。

      网上的证明(雾?)

     http://blog.chinaunix.net/uid-26510579-id-3183558.html

     http://www.zybang.com/question/673815bbe56e8b5639f95234b515b8c5.html

      这题把哈密顿回路看成圆,就变成圆上的点之间的边是否能不相交。。和某次模拟赛的T3一模一样= =

      显然对于两条会相交的边x,y,x和y既不能同时在圆内,也不能同时在圆外。。。就转换成2-sat问题了。。

      若使x表示x在圆内,x'表示x在圆外,因为x,y不能同时在圆内,所以连上(x,y')和(y,x'),然后还不能同时在圆外,就再连(x',y)和(y',x)。

      然后就是模板了。。。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=204;
    const int maxm=723333;
    struct zs{
        int too,pre;
    }e[maxm];
    struct zzs{
        int from,too;
    }a[maxn*3];
    int last[maxn*3*2],dfn[maxn*3*2],low[maxn*3*2],st[maxn*3*2],bel[maxn*3*2];
    bool ins[maxn*3*2];
    int from[maxn*3],too[maxn*3],id[maxn];
    int tot,tim,num,i,j,k,n,m,x,y,top,tt;
    inline bool cant(int x,int b){
        if(a[x].from>a[b].from)swap(x,b);
        if(a[b].from>a[x].from&&a[b].from<a[x].too&&a[b].too>a[x].too)return 1;
        return 0;
    }
    void insert(int a,int b){
    //    printf("%d-->%d
    ",a,b);
        e[++tot].too=b;e[tot].pre=last[a];last[a]=tot;
        e[++tot].too=a;e[tot].pre=last[b];last[b]=tot;
    }
    void tarjan(int x){
        dfn[x]=low[x]=++tim;
        st[++top]=x;;ins[x]=1;
        for(int i=last[x];i;i=e[i].pre)if(!dfn[e[i].too]){
            tarjan(e[i].too);low[x]=min(low[x],low[e[i].too]);
        }else if(ins[e[i].too])low[x]=min(low[x],dfn[e[i].too]);
        if(dfn[x]==low[x]){
            num++;
            while(st[top+1]!=x){
                ins[st[top]]=0;bel[st[top]]=num;
                top--;
            }
        }
    }
    bool cmp(zzs a,zzs b){
        return a.from<b.from||(a.from==b.from&&a.too<b.too);
    }
    int main(){
        scanf("%d",&tt);
        while(tt--){
            scanf("%d%d",&n,&m);
            if(m>n*3-6){
                for(i=1;i<=m<<1;i++)scanf("%d",&j);
                for(i=1;i<=n;i++)scanf("%d",&j);
                printf("NO
    ");continue;
            }
            top=tim=tot=num=0;
            memset(dfn,0,4*(2*m+1));
            memset(last,0,4*(2*m+1));
            for(i=1;i<=m;i++)scanf("%d%d",&a[i].from,&a[i].too);
                
            for(i=1;i<=n;i++)scanf("%d",&j),id[j]=i;
            for(i=1;i<=m;i++){
                a[i].from=id[a[i].from];a[i].too=id[a[i].too];
                if(a[i].from>a[i].too)swap(a[i].from,a[i].too);
            }//按哈密顿回路给点重新编号,使1~n依次对应环中的点 
            sort(a+1,a+1+m,cmp);j=0;
            for(i=1;i<=m;i++){
                if(a[i].from+1==a[i].too||a[i].too%n+1==a[i].from)continue;
                j++;
                a[j].from=a[i].from,a[j].too=a[i].too;
            }
            m=j;
            for(i=1;i<m;i++)for(j=i+1;j<=m;j++){
                if(cant(i,j))insert(i*2,j*2-1),insert(j*2,i*2-1);//,printf("%d&&&%d
    ",i,j);
                if(a[j].from>=a[i].too)break;
            }
            for(i=1;i<=2*m;i++)if(!dfn[i])tarjan(i);
            bool flag=0;
            for(i=1;i<=m;i++)if(bel[i*2]==bel[i*2-1]){flag=1;break;
            }
            if(flag)printf("NO
    ");else printf("YES
    ");
        }
        return 0;
    }
    View Code

      系统:正在比对你的代码和黄学长的代码。。。。

         找不到差异QAQ

      当然了kpm大爷那场是玩成括号序列。。。。把边的两端点看成是左括号和右括号,那么圆内和圆外分别是一个合法的括号序列。。算括号序列的时候记录一下每条边会与别的哪些边冲突,按冲突关系建图后二分染色就知道是否可能合法了。。。

      感觉也可以两个括号序列一起上。。其中一个出现冲突后就把冲突的那些边都扔到另外一个括号序列里面,如果再冲突就是无解了。。当然了我只是嘴巴选手(跑

    1997: [Hnoi2010]Planar

    Time Limit: 10 Sec  Memory Limit: 64 MB
    Submit: 1093  Solved: 428
    [Submit][Status][Discuss]

    Description

    Input

    Output

    Sample Input

     

    Sample Output

     

    HINT

     

    Source

    Day1

    //没有样例差评

  • 相关阅读:
    高级选择器
    CSS的选择器
    HTML——标签
    HTML
    并发编程——协程
    并发编程——线程(二)
    并发编程——线程
    4.栈
    3.链表
    2.顺序表
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/4852947.html
Copyright © 2020-2023  润新知