有乙個情報網共有n
nn個人,通過有向的**線聯絡。為保證通訊安全,需要滿足一些要求,這些要求分為兩類:
現在作為總工程師的你需要構造乙個合法的情報網,使得這個情報網滿足給定要求,或者告訴情報機構這樣的情報網是不存在的。
這道題a
aa如果到b
bb的情況一定滿足的話,一定要在滿足這對條件的情況下,其它對盡量難以到達,這是一種貪心的最優策略。因此我們只要將①
①①中的邊連線起來,在判斷②
②②是否合法即可。
那麼我們如何判斷合法呢?顯然我們只需要用tarjan縮點判斷a能否到達b即可。判斷方法就是用陣列暴力標記,類似於二維的dp:f[i
][j]
f[i][j]
f[i][j
]表示當前節點i
ii是否是節點j
jj所能到達的。
這樣轉移的複雜度是不優秀的:o(n
2)
o(n^2)
o(n2).
由於這只是0/1狀態,如果我們使用bitset中的或操作,複雜度可以優化到:o(n
264
)o(\frac)
o(64n2
).此時空間複雜度不允許,我們每一次限制第二維在一定區間內進行多次操作,可以保證時間複雜度不改變,空間複雜度可以進行進一步優化。這種操作的方法類似於分塊來優化空間。
#include
using
namespace std;
const
int n =
1e5+10;
const
int k =
20000
;int n, m,
top(0)
,cnt(0
),scc(0)
, k;
int dfn[n]
, low[n]
, st[n]
, col[n]
, x[n]
, y[n]
, in[n]
, in[n]
, piga[n]
, pigb[n]
;int link1[n]
, tot1 =0;
int link2[n]
, tot2 =0;
struct node e1[n *2]
, e2[n *2]
;bitset < k +
10> f[n]
;int
read
(void
)void
tarjan
(int x)
else
if(in[y]
) low[x]
=min
(low[x]
,dfn[y]);
}if(low[x]
== dfn[x]
)return;}
bool
check
(int l,
int r)
for(
int i=
1;i<=scc;
++i)
while
(q.size()
)}for(
int i=
1;i<=k;
++i)
if(f[col[pigb[i]]]
[col[piga[i]]]
)return0;
return1;
}void
add1
(int x,
int y)
; link1[x]
= tot1;
}void
add2
(int x,
int y)
; link2[x]
= tot2;
}int
main
(void
)for
(int i=
1;i<=n;
++i)
if(dfn[i]==0
)tarjan
(i);
for(
int x=
1,y;x<=n;
++x)
for(
int i=link1[x]
;i;i=e1[i]
.next)
k =read()
;for
(int i=
1;i<=k;
++i)
piga[i]
=read()
, pigb[i]
=read()
;for
(int i=
1,j;i<=scc;i=j+1)
puts
("yes");
printf
("%d\n"
, m)
;for
(int i=
1;i<=m;
++i)
printf
("%d %d\n"
, x[i]
, y[i]);
return0;
}
毒瘤演算法系列3 負環 倍增Floyed
給定一張邊帶權的無向圖g gg,請你找出乙個點數最少的環,使得環上的邊權和為負數。保證圖中不存在重邊和自環。這道題其實最容易想到的時二分,我們去限制邊的長度,判斷是否存在小於等於這個邊權的負環。但是這麼考慮我們實現最後的判斷,我們可以使用倍增來限制邊權的長度。對於每一次的倍增,我們假設需要判定是否存...
毒瘤演算法系列12 最大流 邊雙連通分量 雜湊
給定一張n nn個點 m mm條邊的無向圖,點從1 11開始編號,保證所有點的度數都不超過333。現在假定每條邊的容量都為1 11,請你求出任意兩點間的最大流,最後只要輸出所有點對 i,j i,ji,j i i j 間最大流的和。對於這道題目,突破口便在於任意點的度數不超過333.最大流的定義 兩點...
java演算法系列
棧的概念 棧是一種特殊的線性表,堆疊的資料元素以及資料元素之間的關係和線性表是完全一樣的。差別是線性表是在任意位置進行插入和刪除操作,棧是只允許在固定的一端進行插入和刪除,棧的插入和刪除只允許在棧頂,棧的插入和刪除通常稱為進棧和出棧。資料集合 每個資料元素的資料型別可以是任意的型別 操作的集合 進棧...