[COGS2443] [HZOI 2016]MC之旅:逃離基友
阿新 • • 發佈:2019-01-26
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;
}