【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。

posted @ 2018-03-19 16:43  ONION_CYC  阅读(...)  评论(...编辑  收藏