2-SAT poj 习题代码记录

3207 -- Ikki's Story IV - Panda's Trick (poj.org)icon-default.png?t=LBL2http://poj.org/problem?id=32072-SAT 模板题

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>

#define x first
#define y second

using namespace std;

typedef pair<int,int> pii ;
const int N = 1100 , M = 1e6 ;

int n,m ;
int h[N],e[M],ne[M],idx ;
int dfn[N],low[N],timestamp ;
int stk[N],id[N],top,id_cnt ;
bool ins[N] ;
pii q[N] ;

bool check(int a,int b,int c,int d){  // 检查是否相交
    if(c < b && b < d && a < c || c < a && a < d && b < d) return 1;
    return  0;
}

void add(int a,int b){
    e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ;
}

void tarjan(int u){
    dfn[u] = low[u] = ++ timestamp ;
    stk[++top] = u ,ins[u] = 1 ;

    for(int i = h[u] ; ~ i ; i = ne[i]){
        int j = e[i] ;
        if(!dfn[j]){
            tarjan(j) ;
            low[u] = min(low[u],low[j]) ;
        }
        else if(ins[j]) low[u] = min(low[u],dfn[j]) ;
    }

    if(low[u] == dfn[u]){
        int y ;
        id_cnt ++ ;
        do{
            y = stk[top--],ins[y] = 0 ,id[y] = id_cnt ;
        }while(y != u) ;
    }
}

int main(){
    scanf("%d%d",&n,&m) ;

    memset(h,-1,sizeof h) ;

    for(int i = 0 ; i < m ; i ++) scanf("%d%d",&q[i].x,&q[i].y) ;

    for(int i = 0 ; i < m ; i++){
        for(int j = i + 1; j < m ; j++){
            int a = q[i].x,b = q[i].y ;
            int c = q[j].x,d = q[j].y ;

            if(a > b) swap(a,b) ;
            if(c > d) swap(c,d) ; 
            if(check(a,b,c,d)){
                add(i,j+m) ;
                add(i+m,j) ;
                add(j,i+m) ;
                add(j+m,i) ;
            }
        }
    }

    for(int i = 0 ; i < 2 * m ; i++){
        if(!dfn[i]){
            tarjan(i) ;
        }
    }

    bool flag = 1 ;
    for(int i = 0 ; i < m ; i++){
        if(id[i] == id[i+m]){
            flag = 0 ;
            break ;
        }
    }

    if(flag) puts("panda is telling the truth...") ;
    else puts("the evil panda is lying again") ;

    return 0;
}

3683 -- Priest John's Busiest Day (poj.org)icon-default.png?t=LBL2http://poj.org/problem?id=3683

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>

using namespace std;

const int N = 2100 , M = 5e6 + 100 ;

// 暴力枚举所有的时间

int n ;
struct node
{
    int s,t,d ;
}q[N];
int h[N],e[M],ne[M],idx ;
int dfn[N],low[N],timestamp ;
int stk[N],id[N],top,id_cnt ;
bool ins[N] ;

void add(int a,int b){
    e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ;
}

bool is_overlap(int a,int b,int c,int d){
    if(b <= c || d <= a) return 0 ;
    return 1; 
}

void  tarjan(int u){
    dfn[u] = low[u] = ++ timestamp ;
    stk[++top] = u,ins[u] = 1;

    for(int i = h[u] ; ~ i ; i= ne[i]){
        int j = e[i] ;
        if(!dfn[j]){
            tarjan(j) ;
            low[u] = min(low[u],low[j]) ;
        }
        else if(ins[j]) low[u] = min(low[u],dfn[j]) ;
    }

    if(low[u] == dfn[u]){
        int y ;
        id_cnt ++ ;
        do{
            y = stk[top--],ins[y] = 0 ,id[y] = id_cnt ;
        }while(y != u) ;
    }
}

int main(){
    scanf("%d",&n) ;

    memset(h,-1,sizeof h) ;

    for(int i = 0 ; i < n ; i++){
        int h,m,d ;
        scanf("%d:%d",&h,&m) ;
        q[i].s = h * 60 + m ;
        scanf("%d:%d",&h,&m) ;
        q[i].t = h * 60 + m ;
        scanf("%d",&d) ;
        q[i].d = d ;
    }

    for(int i = 0 ; i < n ; i ++){
        for(int j = i + 1 ; j < n ; j++){
            node a = q[i],b =q[j] ;
            if(is_overlap(a.s,a.s+a.d,b.s,b.s+b.d)) add(i,j+n),add(j,i+n) ;
            if(is_overlap(a.s,a.s+a.d,b.t-b.d,b.t)) add(i,j),add(j+n,i+n) ;
            if(is_overlap(a.t-a.d,a.t,b.s,b.s+b.d)) add(i+n,j+n),add(j,i) ;
            if(is_overlap(a.t-a.d,a.t,b.t-b.d,b.t)) add(i+n,j),add(j+n,i) ;
        }
    }

    for(int i = 0 ; i < 2 * n ; i++){
        if(!dfn[i])
            tarjan(i) ;
    }

    for(int i = 0 ; i < n ; i++){
        if(id[i] == id[i+n]){
            puts("NO") ;
            return 0 ;
        }
    }

    puts("YES") ;
    for(int i = 0 ; i < n ; i++){
        node a = q[i] ;

        if(id[i] < id[i+n]) printf("%02d:%02d %02d:%02d\n",a.s / 60 ,a.s % 60,(a.s + a.d) / 60 ,(a.s + a.d) % 60) ;
        else printf("%02d:%02d %02d:%02d\n",(a.t - a.d) / 60 ,(a.t - a.d) % 60 ,a.t / 60 ,a.t % 60) ;
    }
    return 0;
}

3678 -- Katu Puzzle (poj.org)icon-default.png?t=LBL2http://poj.org/problem?id=3678板子题

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>

using namespace std;

const int N = 210 ,M = 2e6 + 100 ;

int n,m ;
int h[N],e[M],ne[M],idx ;
int dfn[N],low[N],timestamp ;
int stk[N],id[N],top,id_cnt ;
bool ins[N] ;

void add(int a,int b){
    e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ;
}

void tarjan(int u){
    dfn[u] = low[u] = ++timestamp ;
    stk[++top] = u,ins[u] = 1 ;

    for(int i = h[u] ;~ i ; i = ne[i]){
        int j = e[i] ;
        if(!dfn[j]){
            tarjan(j) ;
            low[u] = min(low[u],low[j]) ;
        }
        else if(ins[j]) low[u] = min(low[u],dfn[j]) ;
    }

    if(low[u] == dfn[u]){
        int y ;
        id_cnt ++ ;
        do{
            y = stk[top--],ins[y] = 0,id[y] = id_cnt ;
        }while(y != u) ;
    }
}

int main(){
    scanf("%d%d",&n,&m) ;

    memset(h,-1,sizeof h) ;

    while(m--){
        int a,b,c ;
        char op[10] ;
        scanf("%d%d%d %s",&a,&b,&c,op) ;

        if(*op == 'A'){
            if(c) add(a+n,a),add(b+n,b) ; // 两个都成立
            else add(a,b+n),add(b,a+n) ;  // !a || !b
        }
        else if(*op == 'O'){
            if(c) add(a+n,b),add(b+n,a) ;
            else add(a,a+n),add(b,b+n) ;
        }
        else{
            if(c) add(a,b+n),add(a+n,b),add(b+n,a) ,add(b,a+n);
            else add(a,b),add(a+n,b+n),add(b,a),add(b+n,a+n) ;
        }
    }

    for(int i = 0 ; i < 2 * n ; i++){
        if(!dfn[i])
            tarjan(i) ;
    }

    for(int i = 0 ; i < n ; i++){
        if(id[i+n] == id[i]){
            puts("NO") ;
            return 0 ;
        }
    }

    puts("YES") ;
    return 0;
}

3648 -- Wedding (poj.org)icon-default.png?t=LBL2http://poj.org/problem?id=3648

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>

using namespace std;

const int N = 210 , M = 2e4 + 100 ;

int n,m ;
int h[N],e[M],ne[M],idx ;
int dfn[N],low[N],timestamp ;
int stk[N],id[N],top,id_cnt ;
bool ins[N] ;
char ans[N] ;

void init(){
    idx = timestamp = id_cnt = 0 ;
    memset(h,-1,sizeof h) ;
    memset(dfn,0,sizeof dfn) ;
    memset(ins,0,sizeof ins) ;
}

int get(char x,int a,int t){
    if(x == 'h'){
        if(!t) return a ;
        return 2 * n + a ;
    }
    else{
        if(!t) return n + a;
        return 3 * n + a ; 
    }
}

void add(int a,int b){
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

void tarjan(int u){
    dfn[u] = low[u] = ++ timestamp ;
    stk[++top] = u,ins[u] = 1;

    for(int i = h[u] ;~i  ;i = ne[i]){
        int j = e[i] ;
        if(!dfn[j]){
            tarjan(j) ;
            low[u] = min(low[u],low[j]) ;
        }
        else if(ins[j]) low[u] = min(low[u],dfn[j]) ;
    }

    if(low[u] == dfn[u]){
        int y ;
        id_cnt++ ;
        do{
            y = stk[top--],ins[y] = 0,id[y] = id_cnt ;
        }while(y != u) ;
    }
}

int main(){
    
    while(scanf("%d%d",&n,&m),n || m){
        init() ;

        while(m--){
            int a,b ;
            char x,y ;
            scanf("%d%c%d%c",&a,&x,&b,&y) ;
            // 分析,将与新娘坐在一侧视为0,与新郎坐在一侧视为1
            // 这是有通奸关系,所以不能同时坐在新娘对面

            add(get(x,a,1),get(y,b,0)),add(get(y,b,1),get(x,a,0)) ;
        }

        for(int i = 0 ; i < n ; i ++){
            // 两个不能坐在同一侧,
            char x = 'h',y = 'w' ;
            add(get(x,i,0),get(y,i,1)),add(get(y,i,0),get(x,i,1)) ;
        }

        add(get('w',0,1),get('w',0,0)) ;

        for(int i = 0 ; i < 4 * n; i++)
            if(!dfn[i])
                tarjan(i) ;

        bool flag = 1 ;
        for(int i = 0 ; i < 2 * n ; i ++){
            if(id[i] == id[i + 2 * n]){
                flag = 0 ;
                break ;
            }
        }


        if(!flag){
            puts("bad luck") ;
            continue ;
        }

        for(int i = 0 ; i < 2 * n;  i++){
            if(id[i] < id[i + 2 * n]){
                if(i < n) ans[i] = 'h' ;
                else ans[i-n] = 'w' ;
            }
        }

        for(int i = 1 ; i < n  ; i++){
            printf("%d%c ",i,ans[i]) ;
        }

        puts("") ;
    }
    return 0;
}

2723 -- Get Luffy Out (poj.org)icon-default.png?t=LBL2http://poj.org/problem?id=2723

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>

#define x first
#define y second

using namespace std;

typedef pair<int,int> pii ;
const int N = 4100 , M = 2 * N ;

// http://poj.org/problem?id=2723
// 由题目分析可得到,当可以开开i个门,那么一定可以开开i-1个门,那么说开门数量是具有单调性的
// 由于具有单调性,所以可以使用二分来解决
// 那么是二分的话,据需要写一个合适的检查函数
// 那么检查函数需要找到选前mid个门能否成立
// 那么这就转化为一个2-SAT问题,是否成立了。
// 每对钥匙a,b是选了 a -> !b ,b -> !a ;
// 每对门a,b是a || b, !a - > b,!b - > a;

int n,m ;
int h[N],e[M],ne[M],idx ;
int dfn[N],low[N],timestamp ;
int stk[N],id[N],top,id_cnt ;
bool ins[N] ;
pii key[N],q[N] ;

void init(){
    idx = timestamp = id_cnt = 0 ;
    memset(h,-1,sizeof h) ;
    memset(dfn,0,sizeof dfn) ;
}

void add(int a,int b){
    e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ;
}

void tarjan(int u){
    dfn[u] = low[u] = ++ timestamp ;
    stk[++top] = u ,ins[u] = 1 ;

    for(int i = h[u] ; ~ i ; i = ne[i]){
        int j = e[i] ;
        if(!dfn[j]){
            tarjan(j) ;
            low[u] = min(low[u],low[j]) ;
        }
        else if(ins[j]) low[u] = min(low[u],dfn[j]) ;
    }

    if(low[u] == dfn[u]){
        int y ;
        id_cnt ++ ;
        do{
            y =stk[top--],ins[y] = 0,id[y] = id_cnt ;
        }while(y != u) ;
    }
}

bool check(int m){
    init() ;

    for(int i = 0 ; i < n ; i++){
        add(key[i].x,key[i].y + 2 * n),add(key[i].y ,key[i].x + 2 * n) ;
    }

    for(int i = 0 ; i < m; i++){
        add(q[i].x + 2 * n,q[i].y),add(q[i].y + 2 * n,q[i].x) ;
    }

    for(int i = 0 ; i < 4 * n ; i++){
        if(!dfn[i])
            tarjan(i) ;
    }

    for(int i = 0 ; i < 2 * n ; i++){
        if(id[i] == id[i + 2 * n]){
            return 0 ;
        }
    }
    
    return 1 ;
}

int main(){
    while(scanf("%d%d",&n,&m),n || m){
        for(int i = 0 ; i < n ; i ++) scanf("%d%d",&key[i].x,&key[i].y) ;
        
        for(int i = 0 ; i < m ; i++) scanf("%d%d",&q[i].x,&q[i].y) ;

        int l = 1 , r = m ;

        while(l < r){
            int mid = l + r + 1 >> 1 ;
            if(check(mid)) l = mid ;
            else r = mid - 1;
        }

        printf("%d\n",l) ;
    }

    return 0;
}


2749 -- Building roads (poj.org)icon-default.png?t=LBL2http://poj.org/problem?id=2749 

数组二分

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <vector>
#include <cmath>

#define x first
#define y second

using namespace std;

typedef pair<int,int> pii ;
const int N = 1100 , M = 2e6 + 100 ;

// 同上一题
// 都是二分答案
// 这里二分的时候从数组中二分,由于是整数值,也可以直接二分

int n,A,B,dist_s1_s2 ;
int h[N],e[M],ne[M],idx ;
int dfn[N],low[N],timestamp ;
int stk[N],id[N],top,id_cnt ;
bool ins[N] ;
pii obv[N],fir[N] ;
pii q[N],dist[N],s1,s2 ;
vector<int> nums ;

int get_dist(pii &a,pii &b){
    return abs(a.x-b.x) + abs(a.y-b.y) ;
}

void init(){
    idx = timestamp = id_cnt = 0 ;
    memset(h,-1,sizeof h) ;
    memset(dfn,0,sizeof dfn) ;
}

void add(int a,int b){
    e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ;
}

void tarjan(int u){
    dfn[u] = low[u] = ++ timestamp ;
    stk[++top] = u,ins[u] = 1 ;

    for(int i = h[u] ;~ i ; i = ne[i]){
        int j = e[i] ;
        if(!dfn[j]){
            tarjan(j) ;
            low[u] = min(low[u],low[j]) ;
        }
        else if(ins[j]) low[u] = min(low[u],dfn[j]) ;
    }

    if(low[u] == dfn[u]){
        int y ;
        id_cnt ++ ;
        do{
            y = stk[top--],ins[y] = 0,id[y] = id_cnt ; 
        }while(y != u) ;
    }
}

bool check(int mid){
    init() ;

    for(int i = 0 ; i < A ; i++){
        int a = obv[i].x,b = obv[i].y ;
        add(a,b+n),add(a+n,b) ;
        add(b,a+n),add(b+n,a) ;
    }

    for(int i = 0 ; i < B; i++){
        int a = fir[i].x ,b = fir[i].y ;
        add(a,b),add(a+n,b+n) ;
        add(b,a),add(b+n,a+n) ;
    }

    for(int i = 0 ; i < n ; i ++){
        for(int j =  i + 1 ; j < n ; j ++){
            int a = i + 1 ,b = j + 1 ;
            if(dist[i].x + dist[j].x > nums[mid]) add(a,b+n),add(b,a+n) ;
            if(dist[i].y + dist[j].y > nums[mid]) add(a+n,b),add(b+n,a) ;
            if(dist[i].x + dist[j].y + dist_s1_s2 > nums[mid]) add(a,b),add(b+n,a+n) ;
            if(dist[i].y + dist[j].x + dist_s1_s2 > nums[mid]) add(b,a),add(a+n,b+n) ; 
        }
    }

    for(int i = 1 ; i <= 2 * n ; i++){
        if(!dfn[i])
            tarjan(i) ;
    }

    for(int i = 1 ; i <= n ; i++){
        if(id[i] == id[i+n]) return 0 ;
    }

    return 1 ;
}

int main(){
    scanf("%d%d%d",&n,&A,&B) ;
    scanf("%d%d%d%d",&s1.x,&s1.y,&s2.x,&s2.y) ;

    dist_s1_s2 = get_dist(s1,s2) ;
    for(int i = 0 ; i < n ;  i++){
        scanf("%d%d",&q[i].x,&q[i].y) ;
        dist[i].x = get_dist(q[i],s1) ;
        dist[i].y = get_dist(q[i],s2) ;
    }

    for(int i = 0 ; i < n ; i ++){
        for(int j =  i + 1 ; j < n ; j ++){
            nums.push_back(dist[i].x+dist[j].x) ;  // 分为四种情况,都连接s1,都连接s2,第一个连接s1第二个连接s2,第一个连接s2,第二个连接s1
            nums.push_back(dist[i].y+dist[j].y) ;
            nums.push_back(dist[i].x+dist[j].y + dist_s1_s2) ;
            nums.push_back(dist[i].y+dist[j].x + dist_s1_s2) ;
        }
    }

    for(int i = 0 ; i < A ; i ++) scanf("%d%d",&obv[i].x,&obv[i].y) ;

    for(int i = 0 ; i < B ; i++) scanf("%d%d",&fir[i].x,&fir[i].y) ;

    sort(nums.begin(),nums.end()) ;
    nums.erase(unique(nums.begin(),nums.end()),nums.end()) ;
    nums.push_back(1e9) ;
    //for(int i : nums) cout << i << endl ; 

    int l = 0, r = nums.size() - 1;
    while(l < r){
        int mid = l + r >> 1 ;
        if(check(mid)) r = mid ;
        else l = mid + 1 ;
    }
    nums.back() = -1 ;

    printf("%d\n",nums[l]) ;

    return 0;
}

直接二分

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <vector>
#include <cmath>

#define x first
#define y second

using namespace std;

typedef pair<int,int> pii ;
const int N = 1100 , M = 2e6 + 100 ;

int n,A,B,dist_s1_s2 ;
int h[N],e[M],ne[M],idx ;
int dfn[N],low[N],timestamp ;
int stk[N],id[N],top,id_cnt ;
bool ins[N] ;
pii obv[N],fir[N] ;
pii q[N],dist[N],s1,s2 ;
vector<int> nums ;

int get_dist(pii &a,pii &b){
    return abs(a.x-b.x) + abs(a.y-b.y) ;
}

void init(){
    idx = timestamp = id_cnt = 0 ;
    memset(h,-1,sizeof h) ;
    memset(dfn,0,sizeof dfn) ;
}

void add(int a,int b){
    e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ;
}

void tarjan(int u){
    dfn[u] = low[u] = ++ timestamp ;
    stk[++top] = u,ins[u] = 1 ;

    for(int i = h[u] ;~ i ; i = ne[i]){
        int j = e[i] ;
        if(!dfn[j]){
            tarjan(j) ;
            low[u] = min(low[u],low[j]) ;
        }
        else if(ins[j]) low[u] = min(low[u],dfn[j]) ;
    }

    if(low[u] == dfn[u]){
        int y ;
        id_cnt ++ ;
        do{
            y = stk[top--],ins[y] = 0,id[y] = id_cnt ; 
        }while(y != u) ;
    }
}

bool check(int mid){
    init() ;

    for(int i = 0 ; i < A ; i++){
        int a = obv[i].x,b = obv[i].y ;
        add(a,b+n),add(a+n,b) ;
        add(b,a+n),add(b+n,a) ;
    }

    for(int i = 0 ; i < B; i++){
        int a = fir[i].x ,b = fir[i].y ;
        add(a,b),add(a+n,b+n) ;
        add(b,a),add(b+n,a+n) ;
    }

    for(int i = 0 ; i < n ; i ++){
        for(int j =  i + 1 ; j < n ; j ++){
            int a = i + 1 ,b = j + 1 ;
            if(dist[i].x + dist[j].x > mid) add(a,b+n),add(b,a+n) ;
            if(dist[i].y + dist[j].y > mid) add(a+n,b),add(b+n,a) ;
            if(dist[i].x + dist[j].y + dist_s1_s2 > mid) add(a,b),add(b+n,a+n) ;
            if(dist[i].y + dist[j].x + dist_s1_s2 > mid) add(b,a),add(a+n,b+n) ; 
        }
    }

    for(int i = 1 ; i <= 2 * n ; i++){
        if(!dfn[i])
            tarjan(i) ;
    }

    for(int i = 1 ; i <= n ; i++){
        if(id[i] == id[i+n]) return 0 ;
    }

    return 1 ;
}

int main(){
    scanf("%d%d%d",&n,&A,&B) ;
    scanf("%d%d%d%d",&s1.x,&s1.y,&s2.x,&s2.y) ;

    dist_s1_s2 = get_dist(s1,s2) ;
    for(int i = 0 ; i < n ;  i++){
        scanf("%d%d",&q[i].x,&q[i].y) ;
        dist[i].x = get_dist(q[i],s1) ;
        dist[i].y = get_dist(q[i],s2) ;
    }

    // for(int i = 0 ; i < n ; i ++){
    //     for(int j =  i + 1 ; j < n ; j ++){
    //         nums.push_back(dist[i].x+dist[j].x) ;  // 分为四种情况,都连接s1,都连接s2,第一个连接s1第二个连接s2,第一个连接s2,第二个连接s1
    //         nums.push_back(dist[i].y+dist[j].y) ;
    //         nums.push_back(dist[i].x+dist[j].y + dist_s1_s2) ;
    //         nums.push_back(dist[i].y+dist[j].x + dist_s1_s2) ;
    //     }
    // }

    for(int i = 0 ; i < A ; i ++) scanf("%d%d",&obv[i].x,&obv[i].y) ;

    for(int i = 0 ; i < B ; i++) scanf("%d%d",&fir[i].x,&fir[i].y) ;

    // sort(nums.begin(),nums.end()) ;
    // nums.erase(unique(nums.begin(),nums.end()),nums.end()) ;
    // nums.push_back(1e9) ;
    //for(int i : nums) cout << i << endl ; 

    int l = 0, r = 1e9;
    while(l < r){
        int mid = l + r >> 1 ;
        if(check(mid)) r = mid ;
        else l = mid + 1 ;
    }
    // nums.back() = -1 ;
    if(l == 1e9) l = -1 ;

    printf("%d\n",l) ;

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值