題目鏈結
模板題,先使用 \(tarjan\) 進行縮點,然後重新建邊,最後拓撲排序即可
在有向圖g中,對於點集v'∈v, 點集中的任意兩點都可達,則稱v'為強連通在有向圖中,\(dfs\) 時,我們需要維護 \(dfn\) 和 \(low\),目的在於把所有的強連通分量縮成乙個點(因為題目裡說可以重複走,而強連通分量裡兩點都可以到達)
設 \(dfn_i\) 為遍歷到當前節點 \(i\) 的時間戳,\(low_i\) 為當前節點 \(i\) 能回溯到的最早節點,
當 \(dfn_i = low_i\) 時說明以 \(i\) 為根形成了強連通分量,
此時我們可以用棧來維護當前強連通分量裡的所有點。
此時縮點後的圖是乙個有向無環圖(強連通分量被縮成點),我們考慮使用拓撲排序求出最終的最長路徑
先將入度為 \(0\) 的點進入佇列,然後出隊,將可到達的點的入度減 \(1\) ,然後將當前入度為 \(0\) 點加入佇列,過程中可以 \(dp\) 求出最長路徑
#include #include #include #include #include using namespace std;
const int maxn = 1e4 + 10;
const int maxm = 1e5 + 10;
queue s;
int sta[maxn] ,ind = 0;
vector c[maxn];
int in[maxn];
struct node edge[maxm];
int head[maxn] ,cnt = 0;
void add (int from ,int to)
int n ,m ,answ = 0;
int dis[maxn] ,dis_[maxn];
int tot = 0 ,times = 0;
int dfn[maxn] ,low[maxn] ,ins[maxn] = ,vis[maxn];
void tarjan (int u)
else if (ins[v])
low[u] = min (low[u] ,dfn[v]);
} if (low[u] == dfn[u]) }}
int tot_ = 0;
int dp[maxn];
void toposort ()
} while (! s.empty())
} }}int main ()
for (int q = 1;q <= n;++ q)//tarjan
if (! dfn[q]) tarjan (q);
for (int q = 1;q <= m;++ q)
} toposort ();//拓撲排序
for (int q = 1;q <= tot;++ q)
answ = max (answ ,dp[q]);
printf ("%d\n",answ);
return 0;
}
P3387 模板 縮點
r es ul tresult result h yp erli nk hyperlink hyperl ink de scri ptio ndescription descri ptio n 給定一張n nn個點,m mm條邊的有向圖,點有點權 找出一條路徑使得經過的點的權值和最大,點和邊可以重複...
P3387 模板 縮點
縮點 dp 給定乙個n個點m條邊有向圖,每個點有乙個權值,求一條路徑,使路徑經過的點權值之和最大。你只需要求出這個權值和。允許多次經過一條邊或者乙個點,但是,重複經過的點,權值只計算一次。輸入格式 第一行,n,m 第二行,n個整數,依次代表點權 第三至m 2行,每行兩個整數u,v,表示u v有一條有...
P3387 模板 縮點
題解 qwq論這個題我開了多少陣列qwq 因為每個點走過多次權值只會計算1次 簡化問題 把題目給出的有向圖縮點,成為有向無環圖,然後拓撲排序跑最長路 首先tarjan縮點 然後強連通分量連邊 下面跑拓撲排序,入度為0的強連通分量 first 然後 dis 計算到達這個強連通分量時的最大權值 感覺這裡...