TwoSAT算法模板

该模板来自大白书

【解释】

给多个语句,每个语句为“ Xi为真(假) 或者 Xj为真(假)”

每个变量和拆成两个点 2*i为假, 2*i+1为真

“Xi为真 或 Xj为真”  等价于 “Xi为假 –>  Xj为真”。

DFS算法没有回溯过程。

【函数说明】

模板bfs函数在模板外一般用不到

void init(int n) :初始化

void add(int x,int xval,int y,int yval) :添加边,x,y为节点编号,xval=1表示真,xval=0表示假,yval同理

bool solve() :计算是否存在解。如果存在解返回true,不存在返回false

【变量说明】

vector<int>G[MAXN*2];//邻接表表示图。
bool mark[MAXN*2];//表示某个结点(不是变量)是否已经被访问
int s[MAXN*2],c;//s存储某次DFS访问过那些点。用于重新标记时消去之前访问过的点的记录(mark[]值)

struct Twosat
{
    int n;
    vector<int>G[MAXN*2];
    bool mark[MAXN*2];
    int s[MAXN*2],c;

    bool dfs(int x)
    {
        if(mark[x^1])return 0;//如果x^1被标记过,说明x是不成立(x^1成立),返回0
        if(mark[x])return 1;//如果x被标记过,说明x是成立的,返回1
        mark[x]=1;
        s[c++]=x;
        for(int i=0;i<G[x].size();i++)
        {
            if(!dfs(G[x][i]))return 0;
        }
        return 1;//与之相连的变量都满足。
    }

    void init(int n)//初始化,n为变量个数(结点数2*n,从0开始)
    {
        this->n=n;
        for(int i=0;i<n*2;i++)G[i].clear();
        memset(mark,0,sizeof(mark));
    }

    void add(int x,int xval,int y,int yval)//添加边,xval=1表示真,xval=0表示假,yval同理
    {
        x=x*2+xval;
        y=y*2+yval;
        G[x^1].push_back(y);
        G[y^1].push_back(x);
    }

    bool solve()//计算。
    {
        for(int i=0;i<n*2;i+=2)
        {
            if(!mark[i]&&!mark[i+1])
            {
                c=0;
                if(!dfs(i))//如果”Xi为假”这个假定不成立
                {
                    while(c>0)mark[s[--c]]=0;
                    if(!dfs(i+1))return 0;//改成”Xi为真”,重新标记。
                }
            }
        }
        return 1;
    }
}sat;
时间: 2024-08-11 05:46:09

TwoSAT算法模板的相关文章

tarjan算法模板

var {left表示点 root 没离开栈 vis表示点 root 有没有被访问过} i,n,m,now,time,color,top:longint; v:array[0..10001] of record start:longint;end; e:array[0..100001] of record y,next:longint;end; dfn,low,stack,encolor:array[0..10001] of longint; vis,left:array[0..10001] o

prim算法模板

var g:array[1..10,1..10] of longint; d:array[1..10] of longint; f:array[1..10] of boolean; procedure prim; var i,j,k,min:longint; begin fillchar(g,sizeof(g),0); fillchar(f,sizeof(f),0); for i:=1 to n do d[i]:=g[1,i]; f[1]:=true; for i:=2 to n do begi

bellman-ford算法模板

有SPFA模板,bellman-ford模板显然是多余的. var e:array[1..maxe]of record a,b,w:longint;end; { 距源点s距离 } dis:array[1..maxn]of longint; { 前驱 } pre:array[1..maxn]of longint; m,n,s:longint; procedure relax(u,v,w:longint); begin if dis[u]+w<dis[v] then begin dis[v]:=di

Floyd判最小环算法模板

算法思想:如果存在最小环,会在编号最大的点u更新最短路径前找到这个环,发现的方法是,更新最短路径前,遍历i,j点对,一定会发现某对i到j的最短路径长度dis[i][j]+mp[j][u]+mp[u][i] != INF,这时i,j是图中挨着u的两个点,因为在之前最短路更新过程中,u没有参与更新,所以dis[i][j]所表示的路径中不会出现u,如果成立,则一定是一个环.用Floyd算法来实现.但是对于负环此算法失效,因为有负环时,dis[i][j]已经不能保证i到j的路径上不会经过同一个点多次了.

hdu 1711 KMP算法模板题

题意:给你两个串,问你第二个串是从第一个串的什么位置開始全然匹配的? kmp裸题,复杂度O(n+m). 当一个字符串以0为起始下标时.next[i]能够描写叙述为"不为自身的最大首尾反复子串长度". 当发生失配的情况下,j的新值next[j]取决于模式串中T[0 ~ j-1]中前缀和后缀相等部分的长度, 而且next[j]恰好等于这个最大长度. 防止超时.注意一些细节.. 另外:尽量少用strlen.变量记录下来使用比較好,用字符数组而不用string //KMP算法模板题 //hdu

HDU 2544 最短路(我的dijkstra算法模板、SPAFA算法模板)

思路:这道题是基础的最短路径算法,可以拿来试一下自己对3种方法的理解 dijkstra主要是从第一个点开始枚举,每次枚举出当当前最小的路径,然后再以那最小的路径点为起点,求出它到其它未标记点的最短距离 bellman-ford 算法则是假设有向网中有n 个顶点.且不存在负权值回路,从顶点v1 和到顶点v2 如果存在最短路径,则此路径最多有n-1 条边.这是因为如果路径上的边数超过了n-1 条时,必然会重复经过一个顶点,形成回路:而如果这个回路的权值总和为非负时,完全可以去掉这个回路,使得v1到v

kruskal 算法模板

http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2896 #include <stdio.h> #include <string.h> #include <stdlib.h> struct node { int u,v,w; }q[200001]; int bin[50001]; int n,m,ans; int cmp(const void *a,const void

Floyd算法模板

Floyd可以求出任意两点间的最短距离,代码也相对简单,对于稀疏图来说效率也还是不错的,但由于三个for循环导致时间复杂度较高,不适合稠密图. Floyd算法模板(精简版): void Floyd() { int dist[maxn][maxn]; // dist存储i到j的最短距离 for(int k = 1; k <= n; k++) for(int i = 1;i <= n; i++) for(int j = 1; j <= n; j++) if(dist[i][k] + dist

割点算法模板(Cut-vertex)

下面是求割點的模板,還有cut_vertex_num[]數組(array)記錄了哪些是割點 Int cut_vertex_num[]; void dfs(int cur,int pa) { int child=0,flag=0,i; low[cur]=dfn[cur]=++depth; for(i=0;i<adj[cur].size();i++) { int next=adj[cur][i]; if(!dfn[next]) //若未访问过 { child++; dfs(next,cur); lo