国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

BZOJ 1179: [Apio2009]Atm Tarjan強連通分量縮點,SPFA,DP

2019-11-08 02:23:51
字體:
來源:轉載
供稿:網友

Description 這里寫圖片描述 Input

第一行包含兩個整數N、M。N表示路口的個數,M表示道路條數。接下來M行,每行兩個整數,這兩個整數都在1到N之間,第i+1行的兩個整數表示第i條道路的起點和終點的路口編號。接下來N行,每行一個整數,按順序表示每個路口處的ATM機中的錢數。接下來一行包含兩個整數S、P,S表示市中心的編號,也就是出發的路口。P表示酒吧數目。接下來的一行中有P個整數,表示P個有酒吧的路口的編號 Output

輸出一個整數,表示Banditji從市中心開始到某個酒吧結束所能搶劫的最多的現金總數。 Sample Input 6 7

1 2

2 3

3 5

2 4

4 1

2 6

6 5

10

12

8

16

1 5

1 4

4

3

5

6 Sample Output 47 HINT

50%的輸入保證N, M<=3000。所有的輸入保證N, M<=500000。每個ATM機中可取的錢數為一個非負整數且不超過4000。輸入數據保證你可以從市中心沿著Siruseri的單向的道路到達其中的至少一個酒吧。

解題方法: 首先進行強連通縮點,維護每一個連通分量中,是否有一個點是酒吧,以及總錢數的多少。對縮點后的圖進行拓撲排序,然后按照拓撲排序進行動態規劃。記 dp[i]表示走到點 i 的最大獲利,對于給定的起點屬于的連通塊有 dp[i]=money[i],其余點的初值都是 dp[i]=負無窮。對于一條邊 i 連接 j,我們用 dp[i]+money[j]來更新 dp[j]。答案是滿足一個連通塊中至少有一個是酒吧的強連通分量中最大的 dp[i]。由于會爆棧,強連通分量算法要進行人工堆棧。時間復雜度 O(n+m)。

//bzoj 1179 tarjan spfa#include <bits/stdc++.h>using namespace std;const int maxn = 500005;int n, m, q, S, dfs_clock, cnt, scc, top, ans;int head1[maxn], head2[maxn], dp[maxn];int dfn[maxn], low[maxn], c[maxn], v[maxn], s[maxn], belong[maxn];bool inq[maxn], vis[maxn];struct edge{ int v, nxt; edge(){} edge(int v, int nxt) : v(v), nxt(nxt) {}}E1[maxn*2], E2[maxn*2];void init1(){ cnt = 0; memset(dp, 0, sizeof(dp)); memset(head1, -1, sizeof(head1));}void init2(){ cnt = 0; memset(head2, -1, sizeof(head2));}void addedge1(int u, int v){ E1[cnt].v = v, E1[cnt].nxt = head1[u], head1[u] = cnt++;}void addedge2(int u, int v){ E2[cnt].v = v, E2[cnt].nxt = head2[u], head2[u] = cnt++;}void tarjan(int x){ int now = 0; dfn[x] = low[x] = ++dfs_clock; s[++top] = x; inq[x] = 1; for(int i = head1[x]; ~i; i = E1[i].nxt){ int to = E1[i].v; if(!dfn[to]){ tarjan(to); low[x] = min(low[x], low[to]); } else if(inq[to]){ low[x] = min(low[x], dfn[to]); } } if(low[x] == dfn[x]){ scc++; while(now != x){ now = s[top]; top--; belong[now] = scc; v[scc] += c[now]; inq[now] = 0; } }}void rebuild(){ init2(); for(int i = 1; i <= n; i++){ for(int j = head1[i]; ~j; j = E1[j].nxt){ int to = E1[j].v; if(belong[i] != belong[to]){ addedge2(belong[i], belong[to]); } } }}void spfa(){ queue <int> que; que.push(belong[S]); vis[belong[S]] = 1; dp[belong[S]] = v[belong[S]]; while(!que.empty()){ int now = que.front(); que.pop(); vis[now] = 0; for(int i = head2[now]; ~i; i = E2[i].nxt){ int to = E2[i].v; if(dp[now] + v[to] > dp[to]){ dp[to] = dp[now] + v[to]; if(!vis[to]){ vis[to] = 1; que.push(to); } } } }}int main(){ init1(); scanf("%d%d", &n, &m); for(int i = 1; i <= m; i++){ int u, v; scanf("%d%d", &u, &v); addedge1(u, v); } for(int i = 1; i <= n; i++) scanf("%d", &c[i]); for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i); scanf("%d%d", &S, &q); rebuild(); spfa(); for(int i = 1; i <= q; i++){ int x; scanf("%d", &x); if(dp[belong[x]] > ans) ans = dp[belong[x]]; }
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 桑日县| 武宁县| 台山市| 互助| 枣阳市| 沙坪坝区| 镇坪县| 堆龙德庆县| 桃源县| 高雄县| 桑日县| 武宁县| 渭南市| 论坛| 涞源县| 抚顺县| 义乌市| 石家庄市| 凤山县| 连山| 安康市| 保亭| 双辽市| 枝江市| 湘乡市| 新源县| 枣强县| 汤阴县| 墨竹工卡县| 禹州市| 浦县| 台东县| 十堰市| 新乡县| 西和县| 象山县| 会宁县| 工布江达县| 东乡县| 清镇市| 怀集县|