zoukankan      html  css  js  c++  java
  • 【POJ3207】Ikki's Story IV

    测试地址:Ikki’s Story IV - Panda’s Trick
    题目大意:n个点排成一个环形,现在要连m条边,一条边要么连在环形的里面,要么连在环形的外面,问有没有一种连法使得这些边两两之间不相交(在点上相交不算)?
    做法:我的博客已经持续更新一周年了,可喜可贺可喜可贺……
    至于为什么这一个月没有更新呢……说来话长,你们只需要知道我NOI2017考崩了就好(T_T)。
    这一题是一个2-SAT的模型。
    什么叫2-SAT?2-SAT是2-适定性问题的简称,差不多是这样一个模型:给若干个东西,这些东西两两之间可能有限制条件,问有没有满足所有条件的选法。之所以命名为2-SAT就是因为这些限制条件是两两之间的条件,而k-SAT问题在k>2时已经被证明是NPC问题,只有2-SAT有比较优美的解法。
    至于解2-SAT,网上有很多教程,这里就不细讲了,大概就是将每个东西分成两点,分别表示取或不取这个东西(以下称这两个点为A和非A),那么问题就转化为在每组两个点里取且仅取一个点,问有没有满足限制条件的取法。我们可以把两两之间的限制条件变成有向边的形式,通常有向边A->B表示要取A必须也取B,经过一些转化后就可以求解,主要是用强连通分量,这里就不再赘述了。
    那么这一题的模型要转化为2-SAT十分简单,每条边有连里边和连外边两种选择,且只能选择一种,这已经提示了这题是2-SAT。再看限制条件,两条边不能在点外相交。经过探究,两条边在点外相交的充要条件是:两条边没有公共顶点并连在同一侧,且其中一条边的两个端点分别处在另一条边将环分成的两个部分。于是我们判断两条边是不是满足了“没有公共顶点”和最后那个条件(太长懒得写),如果同时满足,那么就说明它们的连法受到限制:不能连在环形的同侧,也就是说,对于冲突的两条边A,B,我们不能同时选择点A和B,也不能同时选点非A和非B。那么应该怎么连边呢?很简单,点A,B不能同时被选,那么就表示选了A就必须选非B,选了B就必须选非A,按照这样的转化连边即可。建完图之后,求图的强连通分量,如果在同一组的两个点处在同一个强连通分量,那么问题无解,否则问题肯定有解。其实可以求出任意一个解,但这题只需要判断有没有解,所以就下次再说啦~
    总的时间复杂度:O(m2),可以通过本题(0ms)。
    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int n,m,a[510],b[510],tot=0,tim=0,tott,first[2010]={0};
    struct {int v,next;} e[2000010];
    int dfn[1010],low[1010],belong[1010]={0},stack[1010]={0},top=0;
    int in[2010]={0};
    bool vis[1010]={0};
    
    void insert(int a,int b)
    {
        e[++tot].v=b;
        e[tot].next=first[a];
        first[a]=tot;
    }
    
    void dfs(int v)
    {
        vis[v]=1;
        dfn[v]=++tim;
        low[v]=dfn[v];
        stack[++top]=v;
        int now=top;
        for(int i=first[v];i;i=e[i].next)
        {
            if (!vis[e[i].v])
            {
                dfs(e[i].v);
                low[v]=min(low[v],low[e[i].v]);
            }
            else if (!belong[e[i].v]) low[v]=min(low[v],dfn[e[i].v]);
        }
        if (low[v]==dfn[v])
        {
            tott++;
            for(int i=now;i<=top;i++)
                belong[stack[i]]=tott;
            top=now-1;
        }
    }
    
    void tarjan()
    {
        for(int i=0;i<2*m;i++)
            if (!vis[i]) dfs(i);
        tott++;
        for(int i=1;i<=top;i++)
            belong[stack[i]]=tott;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&a[i],&b[i]);
            if (a[i]>b[i]) swap(a[i],b[i]);
            for(int j=0;j<i;j++)
            {
                if (a[i]==a[j]||b[i]==a[j]||a[i]==b[j]||b[i]==b[j]) continue;
                bool f1=(a[j]>a[i]&&a[j]<b[i]),f2=(b[j]>a[i]&&b[j]<b[i]);
                if (f1!=f2)
                {
                    insert(2*j,2*i+1);
                    insert(2*j+1,2*i);
                    insert(2*i,2*j+1);
                    insert(2*i+1,2*j);
                }
            }
        }
    
        tott=2*m-1;
        tarjan();
    
        for(int i=0;i<m;i++)
            if (belong[2*i]==belong[2*i+1])
            {
                printf("the evil panda is lying again");
                return 0;
            }
        printf("panda is telling the truth...");
    
        return 0;
    }
    
  • 相关阅读:
    Angular Universal 学习笔记
    SAP Spartacus 如何获得当前渲染页面的 CMS 元数据
    Angular 服务器端渲染的学习笔记(二)
    Angular 服务器端渲染的学习笔记(一)
    第三方外部 Saas提供商如何跟使用 SAP 系统的客户进行对接接口集成
    如何从 SAP Spartacus Product Detail 页面,找到其 Angular 实现 Component 的位置
    具备自动刷新功能的 SAP ABAP ALV 报表
    C++学习目录
    c--条件编译
    c--文件读写--二进制
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793621.html
Copyright © 2011-2022 走看看