暖 墟 資料結構高階 2 SAT問題

2022-05-31 08:30:14 字數 4535 閱讀 8858

使用強連通分量。對於每個變數 x,建立兩個點:x,¬x 分別表示變數 x取true和取false

圖的節點個數是兩倍的變數個數在儲存方式上,可以給第 i個變數標號為 i,其對應的反值標號為 i+n

對於每個要求(a∨

b),轉換為 ( ¬a→b )∧(¬b→a ) ,即:「若 a假則 b 必真,若 b 假則 a 必真」。

然後按照箭頭的方向建有向邊,進行相關的縮點、拓撲排序操作,達到題目要求。

1.【洛谷p4782】模板:2-sat問題 

#include#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

typedef

long

long

ll;#define r register

/*【p4782】2-sat問題

有n個布林變數x1​~xn,另有m個需要滿足的條件,

每個條件的形式都是「xi為true/false或xj​為true/false」。

2-sat問題的目標是給每個變數賦值使得所有條件得到滿足。

*/void reads(int &x)

while(s>='

0'&&s<='9')

x*=f; //

正負號}

const

int n=2500019,m=5000019

;int

n,m,dfn[n],low[n],stack[n],vis[n];

int dfn_=0,top_=0,colnum=0,col[n];//

siz[n];

int head[n],tot=0,rd[n],okk=1

;struct nodee[m];

inline

void add(r int x,r int

y)inline

void tarjan(int

x) if(dfn[x]==low[x]) top_--; //

col陣列記錄每個點所在連通塊的編號}}

intmain() for(r int i=1;i<=n*2;i++) if(!dfn[i]) tarjan(i);

for(r int i=1;i<=n;i++) if(col[i]==col[i+n])

if(okk)

else printf("

impossible\n

"); return0;

}

2.【洛谷p4171】滿漢全席 

#include#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

typedef

long

long

ll;#define r register

/*【p4171】滿漢全席

n個材料,每個材料可選滿式或漢式,m個評委各有喜好。

必須滿足每個評委喜歡的兩道菜之一,問是否可能。

*///

對於每樣材料i拆成兩個點,結點i表示滿式,結點i+n表示漢式。

/*每個評委的限制條件都可以看做『或』的形式:

1.mi,mj:連邊i+n到j,表示若i為漢式,則j必須為滿式;

連邊j+n到i,表示若j為漢式,則i必須為滿式

2.mi,hj:連邊i+n到j+n,表示若i為漢式,則j必須為漢式;

連邊j到i,表示若j為滿式,則i必須為滿式

3.hi,hj:連邊i到j+n,表示若i為滿式,則j必須為漢式;

連邊j到i+n,表示若j為滿式,則i必須為漢式

4.hi,mj:連邊i到j,表示若i為滿式,則j必須為滿式;

連邊j+n到i+n,表示若j為漢式,則i必須為漢式

*///

建圖後tarjan求強連通分量, 判斷i和i+n是否屬於同乙個強連通分量,即可行性。

void reads(int &x)

while(s>='

0'&&s<='9')

x*=f; //

正負號}

const

int n=519,m=2519

;int

n,m,dfn[n],low[n],stack[n],vis[n];

int dfn_=0,top_=0,colnum=0

,col[n],siz[n];

int head[n],tot=0,rd[n],okk=0

;struct nodee[m];

inline

void add(r int x,r int

y)inline

void tarjan(int

x) if(dfn[x]==low[x]) top_--; //

col陣列記錄每個點所在連通塊的編號}}

void

init()

char s1[519],s2[519

];int

main()

else

if(s1[0]=='h'

) }

for(r int i=1;i<=n*2;i++) if(!dfn[i]) tarjan(i);

for(r int i=1;i<=n;i++) if(col[i]==col[i+n])

if(okk) printf("

good\n

"); else printf("

bad\n");

}}

3.【poj3207】panda's trick

#include#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

typedef

long

long

ll;#define r register

/*【poj3207】panda's trick

平面上有乙個圓,圓的邊上按順時針放著n個點。

現在要連m條邊(a,b),a到b可以從圓的內部或外部連線。

問能不能連線這m條邊,使這些邊都不相交。

*//*

【分析】設邊i連線點a,b,邊j連線點c,d

線段i與j在圓內是否相交就是線段ab與線段cd是否相交

可以證明,如果i與j在圓內不能共存,則在圓外也一定不能共存。

即:i內j外,建邊i−>j′; i外j內,建邊i′−>j;

j內i外,建邊j−>i′; j外i內,建邊j′−>i。

*/void reads(int &x)

while(s>='

0'&&s<='9')

x*=f; //

正負號}

const

int n=5019,m=500019

;int

n,m,dfn[n],low[n],stack[n],vis[n];

int dfn_=0,top_=0,colnum=0

,col[n],u[n],v[n];

int head[n],tot=0,rd[n],okk=0

;struct nodee[m];

int xj(int a,int

b)inline

void add(r int x,r int

y)inline

void tarjan(int

x) if(dfn[x]==low[x]) top_--; //

col陣列記錄每個點所在連通塊的編號}}

bool

solve()

intmain()

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

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

(xj(i,j))

add(i,j+m),add(j,i+m),add(j+m,i),add(i+m,j);

if(solve()) printf("

panda is telling the truth...\n");

else printf("

the evil panda is lying again\n");

}

暖 墟 初級資料結構 分塊

分塊的概念與運用 例題1 單點修改 區間查詢 例題2 區間修改 單點查詢 例題3 區間修改 區間查詢 例題4 bzoj 2724 蒲公英 例題5 bzoj 2038 小z的襪子 通過適當的劃分,預處理一部分資訊並儲存下來。用空間換取時間,達到時空平衡。易實現。將查詢區間分成中間整塊 零散兩邊,此時兩...

資料結構筆記2 資料結構求解問題的過程

1.集合 元素之間的關係 無 特點 資料元素之間 除了屬於同乙個集合 的關係外,別無其他邏輯關係。是最鬆散的,不受任何制約的關係。2.線性關係 元素之間的關係 一對一 特點 開始元素和終端元素都是唯一的,除此之外,其餘元素都有且僅有乙個前趨元素和乙個後繼元素。3.樹形結構 元素之間的關係 一對多 特...

資料結構 2 用棧實現迷宮問題的求解

反思總結 最近看到一句區別棧和佇列很形象的話 棧是先進後出,佇列是先進先出 所以吃多了吐就是棧,吃多了拉就是佇列 如上面的迷宮,用棧實現求迷宮路徑的程式,所求路徑不需要是最短路徑,但必須是簡單路徑,即在求得的路徑上不能重複出現同一通道塊。比如當走到 1,8 時,發現無路可走了,則依次退棧,退到能走通...