洛谷P5782 【[POI2001]和平委员会】

2-SAT问题模板

先看两道例题:

【模板】2-SAT 问题

满汉全席

在搞懂上面的题后,这题就并不难了。

最主要的就是跑tarjan和连边。

比如说:a,b为一个党派,c,d为一个党派,且a,c有仇,那么只能选a,d或b,c。也就是说要在a,d之间连一条边,在b,c之间连一条边。

上述操作完成后,tarjan跑一边缩点,如果同一个党派的两人在同一个强连通分量里,那么和平委员会就不能创立。~~(别告诉我你连tarjan都不会)~~

代码如下

邻接表做法:

#include<bits/stdc++.h>
using namespace std;
vector<int>g[16005];
stack<int>s;
int n,m,a,b,ind,cnt,dfn[16005],low[16005],scc[16005],opp[16005],val[16005];
bool f,vis[16005];
void tarjan(int u){
    dfn[u]=low[u]=++ind;
    s.push(u);
    vis[u]=1;
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i];
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }else if(vis[v])low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        cnt++;
        int v;
        do{
            v=s.top();
            s.pop();
            scc[v]=cnt;
            vis[v]=0;
        }while(u!=v);
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&a,&b);
        g[a].push_back(b&1?b+1:b-1);
        g[b].push_back(a&1?a+1:a-1);
    }
    for(int i=1;i<=n*2;i++)if(!dfn[i])tarjan(i);
    for(int i=1;i<=n*2;i+=2){
        if(scc[i]==scc[i+1]){
            f=1;
            break;
        }
    }
    if(f)printf("NIE");
    else for(int i=1;i<=2*n;i++)if(scc[i]<scc[i&1?i+1:i-1])printf("%d
",i);
}

 前向星做法:

#include<bits/stdc++.h>
using namespace std;
struct edge{
    int next,to;
}ed[32005];
stack<int>s;
int n,m,a,b,num,head[16005],ind,cnt,dfn[16005],low[16005],scc[16005],opp[16005],val[16005];
bool f,vis[16005];
void add(int u,int v){
    num++;
    ed[num].to=v;
    ed[num].next=head[u];
    head[u]=num;
}
void tarjan(int u){
    dfn[u]=low[u]=++ind;
    s.push(u);
    vis[u]=1;
    for(int i=head[u];i;i=ed[i].next){
        int v=ed[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }else if(vis[v])low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        cnt++;
        int v;
        do{
            v=s.top();
            s.pop();
            scc[v]=cnt;
            vis[v]=0;
        }while(u!=v);
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&a,&b);
        add(a,b&1?b+1:b-1);
        add(b,a&1?a+1:a-1);
    }
    for(int i=1;i<=n*2;i++)if(!dfn[i])tarjan(i);
    for(int i=1;i<=n*2;i+=2){
        if(scc[i]==scc[i+1]){
            f=1;
            break;
        }
    }
    if(f)printf("NIE");
    else for(int i=1;i<=2*n;i++)if(scc[i]<scc[i&1?i+1:i-1])printf("%d
",i);
}
对比:邻接表占空间少,但比较慢;前向星占空间多,但比较快。反正都能过
原文地址:https://www.cnblogs.com/gzezzry/p/12109197.html