[COGS2443] [HZOI 2016]MC之旅:逃離基友

HZOI是衡水中學信息學奧林匹克競賽的縮寫。

題意

有n對寶石,給出所有寶石之間的限制關係以下列格式,要求所有表達式值爲真

 1: i       //表示編號爲i的鑽石礦一定需要挖去
 2: not i   //表示編號爲i的鑽石礦一定不可以被挖去
 3: i and j
 4: i and (not j)
 5: i or j
 6: i or (not j)
 7: not (i and j)
 8: not (i or j)
 9: i xor j //表示異或,即當i=true,j=false或i=false,j=true是表達式爲true
10: not (i xor j)
11: i xor (not j)
12: (not i) or (not j)

要求選出n個寶石,每對寶石中選出一個,且滿足所有限制,且字典序最小,輸出方案;無答案輸出“die”

題解

紅果果的2-SAT問題。
講解在這裏
這道題用到了O(nm)的算法,按照字典序枚舉再檢查,但實際複雜度低於O(nm)。

代碼

/// by ztx
/// blog.csdn.net/hzoi_ztx
// 2-SAT
#include <bits/stdc++.h>
#define Rep(i,l,r) for(i=(l);i<=(r);++i)
#define rep(i,l,r) for(i=(l);i< (r);++i)
#define Rev(i,r,l) for(i=(r);i>=(l);--i)
#define rev(i,r,l) for(i=(r);i> (l);--i)
#define Each(i,v)  for(i=v.begin();i!=v.end();++i)
#define r(x)   read(x)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
    ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
    if (CH == '-') NEG = true , CH = getchar() ;
    while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
    if (NEG) ret = -ret ;
}

#define  kN  10010LL
#define  kM  10010LL
#define  x(i)  (i*2)
#define  y(i)  (i*2+1)
#define  t(p)  e[0][p]
#define  n(p)  e[1][p]

template<typename TP>inline bool MA(TP&a,const TP&b) { return a < b ? a=b,true : false; }
template<typename TP>inline bool MI(TP&a,const TP&b) { return a > b ? a=b,true : false; }

int e[2][kM*4], st[kN*2], te = 0;

inline void Add(int u,int v) { te ++ , t(te) = v, n(te) = st[u], st[u] = te; }

int dfn[kN*2], low[kN*2], idx, sta[kN*2], top, mark[kN*2], cnt, belong[kN*2];
bool del[kN*2], ins[kN*2];

void dfs(int u) {
    int p, v;
    dfn[u] = low[u] = ++idx;
    sta[++top] = u, ins[u] = true;
    for (p = st[u]; v = t(p), p; p = n(p))
        if (!dfn[v]) dfs(v), MI(low[u],low[v]);
        else if (ins[v]) MI(low[u],dfn[v]);
    if (dfn[u] == low[u])
        for (cnt++; u!=v;) {
            v = sta[top--], ins[v] = false;
            belong[v] = cnt;
        }
}

bool dfs2(int u) {
    if (mark[u] == 1) return true;
    if (mark[u] == 2) return false;
    if (del[u]) return false;
    sta[++top] = u, mark[u] = 1, mark[u^1] = 2;
    for (int p = st[u]; p; p = n(p))
        if (!dfs2(t(p))) return false;
    return true;
}

int main() {
    freopen("T3_.in","r",stdin), freopen("T3_.out","w",stdout);
    int n, m, i, t, a, b;
    while (scanf("%d%d", &n, &m) != EOF) {
        /// clear
        te = 0;
        rev (i,y(n),1) del[i] = dfn[i] = mark[i] = st[i] = 0;
        top = cnt = idx = 0;
        /// building1
        while (m --> 0) {
            r(t), r(a), ++ a;
            // x_i = a*2  y_i = a*2+1
            if (t == 1) { del[a^1] = true; continue; }
            if (t == 2) { del[a] = true; continue; }
            r(b), ++ b;
            if (t == 7 || t == 12) {
                Add(a,b^1), Add(b,a^1); continue;
            }
            if (t == 10 || t == 11) {
                Add(a,b), Add(b,a), Add(a^1,b^1), Add(b^1,a^1); continue;
            }
            if (t & 1) {
                if (t == 3) del[a^1] = del[b^1] = true;
                else if (t == 5) Add(a^1,b), Add(b^1,a);
                else if (t == 9) Add(a,b^1), Add(b,a^1), Add(a^1,b), Add(b^1,a);
            } else {
                if (t == 4) del[a^1] = del[b] = true;
                else if (t == 6) Add(a^1,b^1), Add(b,a);
                else if (t == 8) del[a] = del[b] = true;
            }
        }
        /// first judge
        Rep (i,1,n) if (del[x(i)] && del[y(i)]) { puts("die"); goto CON; }
/*        /// Tarjan
        rev (i,y(n),1) if (!dfn[i]) dfs(i);
        /// second judge
        Rep (i,1,n) if (belong[x(i)] == belong[y(i)]) { puts("die"); goto CON; }
實測不用縮點判斷更快。。。
*/
        /// building2 don't need
        /*rev (i,y(n),1) if (!del[i])
            for (a = st[i]; b = t(a), a; a = n(a)) if (!del[b] && belong[b] != belong[i])
                Add2(belong[b],belong[i]);*/
        /// O(n*m)
        Rep (i,1,n) if (!mark[x(i)])
            if (top = 0, !dfs2(x(i))) {
                Rep (a,1,top) mark[sta[a]] = mark[sta[a]^1] = 0;
                if (top = 0, !dfs2(y(i))) { puts("die"); goto CON; }
            }
        Rep (i,1,n)
            printf("%d ", mark[x(i)]==1? x(i)-1: y(i)-1);
        puts("");
        CON:;
    }
    fclose(stdin),fclose(stdout);
    END: getchar(), getchar();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章