2-SAT合集

hdu 1815 Building roads

2-sat问题的特征比较明显,元素的状态可以分成互相对立的两个状态并二者择其一。核心在于如何建边,剩下的套模板就可以解决,这题比较trick的一点在于
if barn1->S1,barn2->S2 then
dis(barn1,barn2 ) == dis(barn1,S1 ) + dis(barn2,S2) + dis(S1,S2)
if barn1->S1,barn2->S1 then

dis(barn1,barn2) == dis(barn1,S1) + dis(barn2,S1)

#include <cstdio>
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <cstring>
#include <queue>
#include <set>
#include <cmath>
#include <map>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
#define urp(i,a,b) for(int i=(a),__tzg_##i=(b); i>=__tzg_##i; --i)
#define rp(i,b) for(int i=(0), __tzg_##i=(b);i<__tzg_##i;++i)
#define rep(i,a,b) for(int i=(a), __tzg_##i=(b);i<__tzg_##i;++i)
#define repd(i,a,b) for(int i=(a), __tzg_##i=(b);i<=__tzg_##i;++i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef pair<int,int> pii;
#define px first
#define py second
const ll mod = 1000000007;
const double eps = 1e-6;
#define mp(a,b) make_pair(a,b)
typedef vector<int> VI;
#define px first
#define py second
const int MAXN = 505;
const int MAXM = 1005;
int N, A, B;
struct Pair {
    int x, y;
    void ipt(int k = 0) {
        scanf("%d%d", &x, &y);
        x += k;
        y += k;
    }
    Pair(int a = 0, int b = 0):x(a),y(b) {}
    int dis(const Pair & a) const {
        return abs(x-a.x) + abs(y-a.y);
    }
} S1, S2, barns[MAXN], like[MAXM], hate[MAXM], len[MAXN];
vector<int> ee1[MAXN*2], ee2[MAXN*2];
int __dis, stk[MAXN*2], top, bl[MAXN*2], cbl, vis1[MAXN*2], vis2[MAXN*2], mx_dis;
void add(int u, int v) {
    ee1[u].push_back(v);
    ee2[v].push_back(u);
}
void init() {
    rp(i, N*2) ee1[i].clear(), ee2[i].clear();
    mst(vis1, 0);
    mst(vis2, 0);
    top = 0;
    cbl = 0;
}
void setState(int dis) {
    rp(i, N) rep(j, i+1, N) {
        if (len[i].x + len[j].x > dis)
            add(i<<1, j<<1|1),
                add(j<<1, i<<1|1);
        if (len[i].x + len[j].y + __dis > dis)
            add(i<<1, j<<1),
                add(j<<1|1, i<<1|1);
        if (len[i].y + len[j].x + __dis > dis)
            add(i<<1|1, j<<1|1),
                add(j<<1, i<<1);
        if (len[i].y + len[j].y > dis)
            add(i<<1|1, j<<1),
                add(j<<1|1, i<<1);
    }
}
void dfs1(int x) {
    vis1[x] = 1;
    rp(i, ee1[x].size())
    if (!vis1[ee1[x][i]])
        dfs1(ee1[x][i]);
    stk[top++] = x;
}
void dfs2(int x) {
    vis2[x] = 1;
    bl[x] = cbl;
    rp(i, ee2[x].size())
    if (!vis2[ee2[x][i]])
        dfs2(ee2[x][i]);
}
void prepare() {
    init();
    rp(i, A) {
        add(hate[i].x*2, hate[i].y*2+1);
        add(hate[i].x*2+1, hate[i].y*2);
        add(hate[i].y*2, hate[i].x*2+1);
        add(hate[i].y*2+1, hate[i].x*2);
    }
    rp(i, B) {
        add(like[i].x*2, like[i].y*2);
        add(like[i].x*2+1, like[i].y*2+1);
        add(like[i].y*2, like[i].x*2);
        add(like[i].y*2+1, like[i].x*2+1);
    }
}
int check() {
    rp(i, 2*N) {
        if (!vis1[i])
            dfs1(i);
    }
    for(int i = top-1; i>=0; --i) {
        if (!vis2[stk[i]])
            dfs2(stk[i]), ++cbl;
    }
    rp(i, N) if (bl[i*2] == bl[i*2+1])
        return 0;
    return 1;
}
void init_main() {
    mx_dis = -1;
    rp(i, N) {
        len[i].x = barns[i].dis(S1);
        len[i].y = barns[i].dis(S2);
        mx_dis = max(mx_dis, len[i].x);
        mx_dis = max(mx_dis, len[i].y);
    }
    __dis = S1.dis(S2);
}
int solve() {
    init_main();
    prepare();
    if (!check()) {
        return -1;
    }
    int st = 0, ed = mx_dis*2+__dis;
    while (st < ed) {
        int md = (st+ed)>>1;
        prepare();
        setState(md);
        if (check())
            ed = md;
        else
            st = md+1;
    }
    return st;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
    while (scanf("%d%d%d", &N, &A, &B) != EOF) {
        S1.ipt(), S2.ipt();
        rp(i, N) barns[i].ipt();
        rp(i, A) hate[i].ipt(-1);
        rp(i, B) like[i].ipt(-1);
        printf("%d\n", solve());
    }
    return 0;
}

spoj TORNJEVI

可以说是相当恶心的一道题,一不小心居然撸了老子200+的代码。既然没人写题解,那就果断来一发吧 :-D
题意:
在一张大小为 RXS 的网格图上,n代表需要被消灭的敌人,T代表炮塔,#代表城堡。
一个炮塔发射两发炮弹,方向要求如题,炮弹沿射线运动,可消灭路径上所有的敌人和炮塔,碰到城堡则停止
求出敌人被全部消灭且炮塔无损失的前提下各个炮塔发射炮弹的方向

看着像网络流,但数据量明显略大,一个炮塔的两发炮弹方向分别只能在 (左|右)(上|下) 中二选一,有点2-sat的味道。但是每个敌人都要被消灭,这个关系的表达就不是2-sat力所能及的了。突破口在于题意明确了必定有解,且炮弹能消灭炮塔,所以对于一个n(x,y),至少存在Ta_1(x, y +|- a)或Tb_2(x +|- b,y)且T和n之间不存在#。如果|Ta|>1则Ta均不能消灭n,Tb同理。基本上就是这种类似的思路,剩下的自己意会。

#include <cstdio>
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <cstring>
#include <queue>
#include <set>
#include <cmath>
#include <map>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
#define urp(i,a,b) for(int i=(a),__tzg_##i=(b); i>=__tzg_##i; --i)
#define rp(i,b) for(int i=(0), __tzg_##i=(b);i<__tzg_##i;++i)
#define rep(i,a,b) for(int i=(a), __tzg_##i=(b);i<__tzg_##i;++i)
#define repd(i,a,b) for(int i=(a), __tzg_##i=(b);i<=__tzg_##i;++i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef pair<int,int> pii;
#define px first
#define py second
const ll mod = 1000000007;
const double eps = 1e-6;
#define mp(a,b) make_pair(a,b)
typedef vector<int> VI;
#define px first
#define py second
const int N = 105;
char mmp[N][N];
int ndx[N][N], sT, sn, r, s, nn;
const int dir[4][2] = {{-1,0}, {0,-1}, {0,1}, {1,0}};
int rdir[4][4];
vector<pii> vT, vn;
vector<VI> vr, rv, bv, blv;
VI rl, color, vis1, vis2, vtk, bl, indu;
int top, cbl;
struct Node {
    int Tdx[4];
    Node() {
        mst(Tdx, -1);
    }
};
vector<Node> Tvn;
inline int getPos(int _dx, int _dir) {
    return (_dx<<2)+_dir;
}
inline int getRev(int _dx, int _dir) {
    return (_dx<<2)+3-_dir;
}
inline int getRev(int x) {
    return (x&0xffffffc) | (3-(x&3));
}
inline void add(int u, int v) {
    vr[u].push_back(v);
    rv[v].push_back(u);
}
void cal(int _dir, int i, int role = 0) {
    pii p;
    if (!role) p = vn[i];
    else p = vT[i];
    for (int _x=p.px+dir[_dir][0], _y=p.py+dir[_dir][1], k=1;
            k&&_x>=0&&_x<r&&_y>=0&&_y<s;
            _x+=dir[_dir][0], _y+=dir[_dir][1]) {
        switch(mmp[_x][_y]) {
        case 'T':
            if (!role)
                Tvn[i].Tdx[_dir] = ndx[_x][_y];
            else
                add(getPos(i, _dir), getRev(i, _dir));
            k = 0;
            break;
        case '#':
            k = 0;
            break;
        case 'n':
            if (role)
                break;
        }
    }
}
void topo() {
    queue<int> q1, q2;
    rp(i, indu.size()) if (indu[i] == 0)
        q1.push(i);
    color.assign(cbl, 0);
    while (!q1.empty()) {
        int cur = q1.front();
        q1.pop();
        if (color[cur]) continue;
        color[cur] = 1;
        rp(i, blv[cur].size()) {
            int pos = getRev(blv[cur][i]);
            q2.push(bl[pos]);
            while (!q2.empty()) {
                pos = q2.front();
                q2.pop();
                if (color[pos]) continue;
                color[pos] = 2;
                rp(j, bv[pos].size())
                if (!color[bv[pos][j]])
                    q2.push(bv[pos][j]);
            }
        }
        rp(i, bv[cur].size()) {
            --indu[bv[cur][i]];
            if (indu[bv[cur][i]] == 0)
                q1.push(bv[cur][i]);
        }
    }
}
void dfs1(int x) {
    vis1[x] = 1;
    rp(i, vr[x].size()) {
        if (!vis1[vr[x][i]])
            dfs1(vr[x][i]);
    }
    vtk[top++] = x;
}
void dfs2(int x) {
    vis2[x] = 1;
    bl[x] = cbl;
    rp(i, rv[x].size()) {
        if (!vis2[rv[x][i]])
            dfs2(rv[x][i]);
    }
}
void init() {
    vis1.assign(rv.size(), 0);
    vis2.assign(rv.size(), 0);
    vtk.assign(rv.size(), 0);
    bl.assign(rv.size(), 0);
    top = 0;
    cbl = 0;
}
void check() {
    rp(i, vr.size()) if (!vis1[i])
        dfs1(i);
    urp(i, top-1, 0) if (!vis2[vtk[i]])
        dfs2(vtk[i]), cbl++;
    blv.assign(cbl, VI());
    rp(i, rv.size())
    blv[bl[i]].push_back(i);
    bv.assign(cbl, VI());
    indu.assign(cbl, 0);
    rp(i, rv.size()) rp(j, rv[i].size()) if (bl[i] != bl[rv[i][j]])
        bv[bl[i]].push_back(bl[rv[i][j]]),
        ++indu[bl[rv[i][j]]];
}

int main() {
#ifndef ONLINE_JUDGE
    // freopen("in.txt", "r", stdin);
#endif
    scanf("%d%d", &r, &s);
    rp(i, r) scanf("%s", mmp[i]);
    rep(i, 0, r)rep(j, 0, s) {
        switch(mmp[i][j]) {
        case 'n':
            vn.push_back(mp(i,j));
            ndx[i][j] = sn++;
            break;
        case 'T':
            vT.push_back(mp(i,j));
            ndx[i][j] = sT++;
            break;
        }
    }
    nn = sT<<1;
    vr.assign(nn<<1, VI());
    rv = vr;
    Tvn.assign(sn, Node());
    rp(i, sT) rp(j, 4) cal(j, i, 1);
    rep(i, 0, sn) {
        rep(j, 0, 4) cal(j, i);
        int da = -1, db = -1, fa, fb;
        if (Tvn[i].Tdx[0] != -1 )
            da = Tvn[i].Tdx[0], fa = 3;
        if (Tvn[i].Tdx[3] != -1 ) {
            if (da != -1)
                da = -1,
                add(getPos(Tvn[i].Tdx[0], 3), getRev(Tvn[i].Tdx[0], 3)),
                add(getPos(Tvn[i].Tdx[3], 0), getRev(Tvn[i].Tdx[3], 0));
            else
                da = Tvn[i].Tdx[3], fa = 0;
        }
        if (Tvn[i].Tdx[1] != -1 )
            db = Tvn[i].Tdx[1], fb = 2;
        if (Tvn[i].Tdx[2] != -1 ) {
            if (db != -1)
                db = -1,
                add(getPos(Tvn[i].Tdx[1], 2), getRev(Tvn[i].Tdx[1], 2)),
                add(getPos(Tvn[i].Tdx[2], 1), getRev(Tvn[i].Tdx[2], 1));
            else
                db = Tvn[i].Tdx[2], fb = 1;
        }
        if (da != -1 && db != -1)
            add(getRev(da, fa), getPos(db, fb)),
                add(getRev(db, fb), getPos(da, fa));
        else if (da != -1)
            add(getRev(da, fa), getPos(da, fa));
        else if (db != -1)
            add(getRev(db, fb), getPos(db, fb));
    }
    init();
    check();
    topo();
    rdir[1][3] = 1;
    rdir[1][0] = 4;
    rdir[2][3] = 2;
    rdir[2][0] = 3;
    rp(i, sT) {
        pii ap = vT[i];
        int dx = ndx[ap.first][ap.second];
        int _x, _y;
        int a = getPos(dx, 0);
        if (color[bl[a]] == 1)
            _x = 0;
        else
            _x = 3;
        a = getPos(dx, 1);
        if (color[bl[a]] == 1)
            _y = 1;
        else
            _y = 2;
        mmp[ap.first][ap.second] = '0' + rdir[_y][_x];
    }
    rp(i, r) puts(mmp[i]);
    return 0;
}










你可能感兴趣的:(2-SAT合集)