NOI2017 遊戲(2 SAT 列舉)

2022-03-17 00:07:55 字數 1411 閱讀 1858

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 中所屬強連通分量中編號小的...