2-sat板子題
如果沒有x這個字元的話,問題變成每個點都有兩種選法,有一些限制,顯然是個2-sat問題,設拆出來的兩個點分別為\(i\)和\(i'\),則對於限制\(x->y\),連邊\((x,y),(y',x')\),跑tarjan即可(2-sat基操嘛。)
即使現在有了x這個字元,我們也可以假裝乙個點仍只有兩種選法,列舉這兩種選法,並且確保\(a,b,c\)至少在一種選法中存在就行了;具體來說,對於每個x,列舉\(a\)和\(b\)中哪乙個不能選就足以表示出所有情況了
一句話就是:列舉將每個x變成a或者b,對每種情況跑最簡單的\(2-sat\)就行了
輸出方案的話比較\(color[i]\)和\(color[i+n]\)即可,具體見輸出部分
時間複雜度\(o(n*2^n)\)
//因為spacial judge,最後一行不要輸出回車
#include#define n 100005
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
int n,m,d,ref[n][3],rev[n][3];
int dfn[n],low[n],c,col,color[n];
int st[n],top;
int ban[10];
char lim[n];
struct r r[n];
struct edge
edge[n<<3];int head[n],cnt;
void add_edge(int from,int to)
//0:a 1:b 2:c
template void read(t &x)
void in()
}void tarjan(int rt)
else if(!color[v]) low[rt]=min(low[rt],dfn[v]);
} if(dfn[rt]==low[rt]) }
bool work()
ref[i][no]=0,ref[i][one]=1,ref[i][two]=2;
rev[i][1]=one,rev[i][2]=two;
} for(int i=1;i<=m;++i) }
for(int i=1,t=(n<<1);i<=t;++i) if(!dfn[i]) tarjan(i);
bool ret=1;
for(int i=1;i<=n;++i) if(color[i]==color[i+n]) ret=0;
return ret;
}int main()
} if(!ok) printf("-1");
return 0;
}
NOI2017 遊戲 2 sat演算法
題目 libreoj 題意 n場遊戲,有三種車abc,給定長度為n的字串,a 表示不能選a,b c 同理,x 表示不限,至多d個 x 有m個限制 i,hi,j,hj 表示如果第i場選擇車hi,那麼第j場必須選擇車hj。求可行方案,或無解。n 10 5,d 8。演算法 2 sat 題解 列舉 x 是 ...
NOI2017 遊戲 解題報告
d 這麼小,你考慮直接對 d 個東西暴力 列舉 x 為 a 或 b c 就不用了,因為 a,b 已經包含 c 了,剩下的就是個 2 sat 問題了 但是你發現有個情況是,在若 a 即 b 時,如果 b 被 ban 了,那麼 a 也要被 ban 我們記錄一下被 ban 的點,然後在球方案的時候判一下 ...
NOI2017 遊戲與2 sat方案輸出
本文介紹了2 sat輸出一種方案的方法與證明,以及一種 o nm 複雜度輸出最小字典序的方法.先判定是否有解,縮點後得到一張dag.對於命題組 i,i 我們選擇 i 和 i 中拓樸序靠後的乙個即可.同時由於tarjan縮點時本來就是拓樸序倒序縮點的,只需要選擇 i 和 i 中所屬強連通分量中編號小的...