• 【BZOJ】3495: PA2010 Riddle 2-SAT算法


    【题意】有n个城镇被分成了k个郡,有m条连接城镇的无向边。要求给每个郡选择一个城镇作为首都,满足每条边至少有一个端点是首都。n,m,k<=10^6。

    【算法】2-SAT,前后缀优化建图

    【题解】每个城镇只有作为首都和不是首都两种选项,即2-sat问题。

    2-sat问题中所有边必须加反向边,下面过程忽略反向边。

    对于一条边(x,y),如果x是0,那么y必须是1,即x-y'。(y-x'是反向边,考虑的时候忽略)

    但是一个郡只有一个首都有点烦,有一种套路叫前后缀优化建图。

    对于每个点x,假设一个点x+n,表示编号<=x的和x同在一个郡的点中是否有首都。

    假设x和y是同一个郡的相邻编号点(y>x),那么:

    1.前缀:(x+n)' - (y+n)'

    2.修改:x' - (x+n)'

    3.只有一个首都:(x+n)' - y

    所以n*4个点和n*8条边,进行2-sat。

    复杂度O(M),M=(m+3*n)*2。

    #include<cctype>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read(){
        int s=0,t=1;char c;
        while(!isdigit(c=getchar()))if(c=='-')t=-1;
        do{s=s*10+c-'0';}while(isdigit(c=getchar()));
        return s*t;
    }
    const int maxn=4000010;
    int n,m,K,first[maxn],tot,c,B[1000010],C[1000010];
    bool mark[maxn];
    struct edge{int v,from;}e[maxn*2];////
    void insert(int u,int v){
        tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;
        tot++;e[tot].v=u^1;e[tot].from=first[v^1];first[v^1]=tot;
    }
    int dfsnum=0,TOT,top,dfn[maxn],low[maxn],st[maxn],belong[maxn];
    void tarjan(int x){
        dfn[x]=low[x]=++dfsnum;
        st[++top]=x;
        for(int i=first[x];i;i=e[i].from)if(!dfn[e[i].v]){
            tarjan(e[i].v);
            low[x]=min(low[x],low[e[i].v]);
        }else if(!belong[e[i].v])low[x]=min(low[x],dfn[e[i].v]);
        if(low[x]==dfn[x]){
            TOT++;
            while(st[top]!=x)belong[st[top--]]=TOT;
            belong[st[top--]]=TOT;
        }
    }
    int main(){
        n=read();m=read();K=read();
        for(int i=1;i<=m;i++){
            int u=read()-1,v=read()-1;
            insert(u<<1,v<<1|1);
        }
        for(int i=0;i<n;i++)insert(i<<1|1,(i+n)<<1|1);///
        for(int k=1;k<=K;k++){
            int w=read(),p,pre=read()-1;B[pre]=k;
            for(int i=2;i<=w;pre=p,i++){
                p=read()-1;B[p]=k;
                insert((pre+n)<<1|1,(p+n)<<1|1);
                insert((pre+n)<<1|1,p<<1);
            }
        }
        for(int i=0;i<n*4;i+=2){
            if(!dfn[i])tarjan(i);
            if(!dfn[i^1])tarjan(i^1);
            if(belong[i]==belong[i^1]){printf("NIE");return 0;}
        }
        printf("TAK");
        return 0;
    }
    View Code

    从这道题开始,我知道了一件事:理论复杂度O(nm)的DFS版2-sat是可以无视随机被卡TLE的。

    嘤嘤嘤T_T。

  • 相关阅读:
    MySQL+Toad for Mysql安装,配置及导入中文数据解决乱码等问题
    Excel日期格式提取year
    arcgis中使用excel中x,y坐标创建点问题
    GIS中栅格数据的拼接
    R 中安装xlsx包缺少java环境解决方案
    R中统计量的中英文解释
    arcgis离海距离的计算
    EXCEL处理数据小技巧
    nginx部署成功却没有办法访问
    Linux安装yum install gcc-c++出错:Could not retrieve mirrorlist http://mirrorlist.centos.org/?release=7&arch=x86_64&repo=os&infra=stock error was 14: curl#6
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8603058.html
Copyright © 2020-2023  润新知