左手翻雲右手覆雨 武俠角色扮演遊戲《俠之信條》1月26日登陸Steam
阿新 • • 發佈:2022-01-22
目錄
題目描述
題目描述
設 GG 為有 nn 個頂點的帶權有向無環圖,GG 中各頂點的編號為 11 到 nn,請設計演算法,計算圖 GG 中 1, n1,n 間的最長路徑。
輸入格式
輸入的第一行有兩個整數,分別代表圖的點數 nn 和邊數 mm。
第 22 到第 (m + 1)(m+1) 行,每行 33 個整數 u, v, wu,v,w(u<vu<v),代表存在一條從 uu 到 vv 邊權為 ww 的邊。
輸出格式
輸出一行一個整數,代表 11 到 nn 的最長路。
若 11 與 nn
不連通,請輸出 -1−1。輸入輸出樣例
輸入 #1複製
2 1 1 2 1
輸出 #1複製
1
說明/提示
【資料規模與約定】
- 對於 20%20%的資料,n \leq 100n≤100,m \leq 10^3m≤103。
- 對於 40%40% 的資料,n \leq 10^3n≤103,m \leq 10^{4}m≤104。
- 對於 100%100% 的資料,1 \leq n \leq 15001≤n≤1500,1 \leq m \leq 5 \times 10^41≤m≤5×104,1 \leq u, v \leq n1≤u,v≤n,-10^5 \leq w \leq 10^5−105≤w≤105。
拓撲排序演算法求解
分析
如果題目不限制從1出發,到n,求到某個點的最長路徑,那麼直接進行拓撲排序,然後每次更新就可以了
但是題目說了從1到n最長路徑,那麼這個路徑之外的點都不用管,所以只更新1能到達的點的最長路徑值就可以了
-
在拓撲排序過程中同步標記1能到的點
-
然後所有點正常拓撲排序,但是更行1到每個點最大值的時候,只需要更新1能到的點的就行,其他1不能到達的點不用管
程式碼
#include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<vector> #include<cstring> using namespace std; const int N = 1510; struct Edge { int to; int w; //從該點到to點的邊的權重 }; vector<Edge> h[N]; //存圖 int d[N]; // 入度 int n, m; bool st[N]; // 標記1能到的點 為 true int maxx[N]; // 從1能到該點的路徑最大值 void add(int a, int b, int weight) { Edge edge; edge.to = b; edge.w = weight; h[a].push_back(edge); } void tor() { // q存節點編號,用int就行 queue<int> q; for(int i = 1; i <= n; i++) { // 如果該點的入度為0,加入佇列中 if(!d[i]) q.push(i); } while(!q.empty()) { int t = q.front(); q.pop(); for(int i = 0; i < h[t].size(); i++) { int j = h[t][i].to; int weight = h[t][i].w; // 標準拓撲操作 d[j]--; if(!d[j]) q.push(j); // 如果1能到t點 if(st[t]) { st[j] = true; // 那麼也一定能到j點,這個時候再更新j點的最大距離 maxx[j] = max(maxx[j], maxx[t] + weight); } } } } int main() { memset(maxx, -1, sizeof maxx); // 初始化到1每個點的最大距離為-1 scanf("%d%d", &n, &m); while(m--) { int a, b, w; scanf("%d%d%d", &a, &b, &w); add(a, b, w); // a -> b d[b]++; // } maxx[1] = 0; st[1] = true; tor(); printf("%d\n", maxx[n]); return 0; }