NOI2017 遊戲 2 sat演算法

2022-04-30 02:36:08 字數 1303 閱讀 8784

【題目】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'是'a'或'b'(如果直接列舉選那輛車複雜度太高,不如利用2-sat來做),這樣有2^d種狀態。

這樣確定字串後,每場比賽就只有兩種選項和m種限制,進行2-sat即可,複雜度o(2^d*m)。(因為每次要初始化,常數還挺大的,uoj很容易被卡tle)

2-sat演算法:連邊後tarjan,如果乙個點和對應點屬於同乙個scc則無解,否則選擇所屬scc編號較小的點。(dfs出棧序就是一種逆拓撲序)

實現細節:直接對每個點開3倍點,然後標記乙個點不用,標記使用點為另外兩個點。還有就是如果x和x'必須強制選x'的話,x向x'連有向邊就可以了(不連對稱邊,這樣雖然沒有對稱性,但是不影響)。

#include#include

#include

using

namespace

std;

const

int n=300010

;int

first[n],f[n],a[n],dfn[n],low[n],st[n],belong[n],dfsnum,tot,tot,top,a[n],b[n],c[n],d[n],n,d,m;

intid[n],op[n];

char

s[n];

struct edgee[n*2

];void insert(int u,int v)

void tarjan(int

x)else

if(!belong[e[i].v])low[x]=min(dfn[e[i].v],low[x]);

if(dfn[x]==low[x])

}bool solve(int

o)

for(int i=1;i<=m;i++)

for(int i=0;i3;i++)if(!f[i]&&!dfn[i])tarjan(i);

for(int i=0;iif(belong[id[i]]==belong[op[id[i]]])return0;

return1;

}char s1[10],s2[10

];int

main()

puts("-1

");return0;

}//learn from hekai

view code

NOI2017 遊戲(2 SAT 列舉)

2 sat板子題 如果沒有x這個字元的話,問題變成每個點都有兩種選法,有一些限制,顯然是個2 sat問題,設拆出來的兩個點分別為 i 和 i 則對於限制 x y 連邊 x,y y x 跑tarjan即可 2 sat基操嘛。即使現在有了x這個字元,我們也可以假裝乙個點仍只有兩種選法,列舉這兩種選法,並...

NOI2017 遊戲與2 sat方案輸出

本文介紹了2 sat輸出一種方案的方法與證明,以及一種 o nm 複雜度輸出最小字典序的方法.先判定是否有解,縮點後得到一張dag.對於命題組 i,i 我們選擇 i 和 i 中拓樸序靠後的乙個即可.同時由於tarjan縮點時本來就是拓樸序倒序縮點的,只需要選擇 i 和 i 中所屬強連通分量中編號小的...

NOI2017 遊戲 解題報告

d 這麼小,你考慮直接對 d 個東西暴力 列舉 x 為 a 或 b c 就不用了,因為 a,b 已經包含 c 了,剩下的就是個 2 sat 問題了 但是你發現有個情況是,在若 a 即 b 時,如果 b 被 ban 了,那麼 a 也要被 ban 我們記錄一下被 ban 的點,然後在球方案的時候判一下 ...