日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

「Note」图论方向 - 图论进阶

發布時間:2025/6/17 编程问答 24 如意码农
生活随笔 收集整理的這篇文章主要介紹了 「Note」图论方向 - 图论进阶 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 2-SAT

1.1. 介紹

對于一些節點,每個節點存在兩個狀態(非 \(0\) 即 \(1\)),我們給出一些如下類型的限制條件:

  • 節點 \(i\) 狀態為 \(1/0\)。
  • 若節點 \(i\) 狀態為 \(1/0\),那么節點 \(j\) 狀態為 \(1/0\)。
  • 節點 \(i,j\ (i\not=j)\) 至少有一個為 \(1/0\)。

2-SAT 算法用于解決類似的問題,每個節點最多只能有兩種狀態。

我們用有向圖表示節點狀態之間的遞推關系,我們設 \(p_i\) 表示節點 \(i\) 狀態為真,我們將上述限制條件寫為表達式并寫為“若 \(p\) ,則 \(q\)”的形式,便于用有向圖表示它們的關系:

  • \(p_i\):若 \(\lnot p_i\),則 \(p_i\)。
  • \(\lnot p_i\):若 \(p_i\),則 \(\lnot p_i\)。
  • \(p_i\lor p_j\):若 \(\lnot p_i\) 則 \(p_j\);若 \(\lnot p_j\) 則 \(p_i\)。
  • \(\lnot p_i\lor\lnot p_j\):若 \(p_i\) 則 \(\lnot p_j\);若 \(p_j\) 則 \(\lnot p_i\)。
  • \(\lnot p_i\lor p_j\):若 \(p_i\) 則 \(p_j\);若 \(\lnot p_j\) 則 \(\lnot p_i\)。

若有 \(p\Rightarrow q\),并且 \(p,q\) 相互矛盾,則 \(p\) 一定為假。

更進一步地,若有 \(p\Leftrightarrow q\),并且 \(p,q\) 相互矛盾,則此限制條件下,無解。

考慮無解的情況在有向圖中的表現形式,即兩個矛盾狀態在圖中處于同一個強連通分量中,我們考慮用 Tarjan 算法進行縮點。

對于一種可行方案則在 \(p_i,\lnot p_i\) 兩個狀態點中選擇拓撲序更小的即可,用 Tarjan 后可省去拓撲排序過程,詳見我其他博客。

1.2. 例題

\(\color{royalblue}{P4782}\)

板子題。

$\text{Code}$:
#include<bits/stdc++.h>
#define LL long long
#define UN unsigned
using namespace std;
//--------------------//
//IO
inline int rd()
{
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
//--------------------//
const int N=2e6+5; int n,m;
//--------------------//
struct Edge
{
int to,nex;
}edge[N];
int tot,head[N];
void add(int from,int to)
{
edge[++tot]={to,head[from]};
head[from]=tot;
return;
} int dcnt,dfn[N],low[N];
int sccnt,scc[N];
int stop,sta[N];
bool stv[N]; void Tarjan(int now)
{
low[now]=dfn[now]=++dcnt;
sta[++stop]=now,stv[now]=true;
for(int to,i=head[now];i;i=edge[i].nex)
{
to=edge[i].to;
if(!dfn[to])
{
Tarjan(to);
low[now]=min(low[now],low[to]);
}
else if(stv[to])
low[now]=min(low[now],dfn[to]);
}
if(low[now]==dfn[now])
{
scc[now]=++sccnt;
stv[now]=false;
while(sta[stop]!=now)
{
scc[sta[stop]]=sccnt;
stv[sta[stop]]=false;
stop--;
}
stop--;
}
return;
}
//--------------------//
int main()
{
scanf("%d%d",&n,&m);
for(int a,x,b,y,i=1;i<=m;i++)
{
scanf("%d%d%d%d",&a,&x,&b,&y);
add(a+(!x)*n,b+y*n);
add(b+(!y)*n,a+x*n);
}
for(int i=1;i<=2*n;i++)
if(!dfn[i])
Tarjan(i);
for(int i=1;i<=n;i++)
if(scc[i]==scc[i+n])
{
printf("IMPOSSIBLE\n");
return 0;
}
printf("POSSIBLE\n");
for(int i=1;i<=n;i++)
if(scc[i]<scc[i+n])
printf("0 ");
else
printf("1 ");
return 0;
}

總結

以上是生活随笔為你收集整理的「Note」图论方向 - 图论进阶的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。