生活随笔
收集整理的這篇文章主要介紹了
圆方树学习笔记
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
圓方樹
一.是什么:
對于一個連通圖,
設所有原來的點為圓點,將每個點雙連通分量縮成一個方點,與相鄰的圓點連邊,不存在圓點之間的邊。
連接兩個方點的圓點都是割點。
二.有什么用:
可以將圖上問題轉化為樹上問題,利用樹的優秀性質做題。
將圓點和方點附上合適的權值,可將圖的問題轉化為樹型DP。
三.具體實現:
tarjan求點雙,
將父節點和棧中點都與點雙連邊。
搜索變為有根樹(可同時DP)。
四.代碼:
1 #include<bits/stdc++.h>
2 using namespace std;
3 const int N=
200006,M=
400006;
4 int head[N],head2[N],low[N],dfn[N],siz[N],w[N],n,m;
5 int deep=
0,cnt=
0,top=
0,s[N],t1,t2,num=
0;
6 long long ans=
0;
7 struct edge
8 {
9 int nxt,to;
10 }e[M<<
1],g[M<<
1];
11 //e為原圖,g為圓方樹的圖
12 inline
int read()
13 {
14 int T=
0,F=
1;
char ch=
getchar();
15 while(ch<
'0'||ch>
'9'){
if(ch==
'-') F=-
1; ch=
getchar();}
16 while(ch>=
'0'&&ch<=
'9') T=(T<<
3)+(T<<
1)+(ch-
48),ch=
getchar();
17 return F*
T;
18 }
//讀入優化
19 inline
void add(
int u,
int v){e[++cnt].nxt=head[u]; e[cnt].to=v; head[u]=
cnt;}
20 inline
void add2(
int u,
int v){g[++cnt].nxt=head2[u]; g[cnt].to=v; head2[u]=
cnt;}
21 void tarjan(
int u)
22 {
23 dfn[u]=low[u]=++deep; s[++top]=u; ++
num;
24 int t;
25 for(
int i=head[u];i,t=e[i].to;i=
e[i].nxt)
26 {
27 if(!
dfn[t])
28 {
29 tarjan(t),low[u]=
min(low[u],low[t]);
30 if(low[t]>=
dfn[u])
31 {
32 ++n; add2(n,u),add2(u,n); ++
w[n];
33 while(s[top+
1]!=t) add2(s[top],n),add2(n,s[top]),++w[n],--
top;
34 //add2表示:將點雙里的圓點與點雙的方點相連
35 }
36 }
37 else low[u]=
min(low[u],dfn[t]);
38 }
39 }
//tarjan
40 void dfs(
int u,
int fa)
41 {
42 printf(
"%d :",u);
43 for(
int i=head2[u];i;i=g[i].nxt)
if(g[i].to!=fa) printf(
" %d",g[i].to);
44 for(
int i=head2[u];i;i=
g[i].nxt)
45 if(g[i].to!=
fa) dfs(g[i].to,u);
46 }
//輸出圓方樹的結構,n為輸入的點數,n'為現在的點數
47 //1~n為圓點,n+1~n'為方點
48 int main()
49 {
50 n=read(),m=
read();
51 for(register
int i=
1;i<=m;++i) t1=read(),t2=
read(),add(t1,t2),add(t2,t1);
52 cnt=
0; t1=
n;
53 for(register
int i=
1;i<=t1;++i)
if(!dfn[i]) top=
0,num=
0,tarjan(i),dfs(i,
0);
54 return 0;
55 }
?
五.題目:
鐵人兩項
戰略游戲
轉載于:https://www.cnblogs.com/ljk123-de-bo-ke/p/10938652.html
總結
以上是生活随笔為你收集整理的圆方树学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。