1. 程式人生 > >P3387 【模板】縮點

P3387 【模板】縮點

輸入輸出格式 無環 ring char != top name 算法 ret

P3387 【模板】縮點

題目背景

縮點+DP

題目描述

給定一個n個點m條邊有向圖,每個點有一個權值,求一條路徑,使路徑經過的點權值之和最大。你只需要求出這個權值和。

允許多次經過一條邊或者一個點,但是,重復經過的點,權值只計算一次。

輸入輸出格式

輸入格式:

第一行,n,m

第二行,n個整數,依次代表點權

第三至m+2行,每行兩個整數u,v,表示u->v有一條有向邊

輸出格式:

共一行,最大的點權之和。

輸入輸出樣例

輸入樣例#1: 復制
2 2
1 1
1 2
2 1
輸出樣例#1: 復制
2

說明

n<=10^4,m<=10^5,|點權|<=1000 算法:Tarjan縮點+DAGdp

分析

縮點成有點無環圖(樹),然後拓撲+dp

code

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<cstdlib>
  6 
  7 using namespace std;
  8 
  9 const int N = 20100;
 10 const
int M = 200100; 11 struct Edge{ 12 int to,nxt; 13 }e[M],s[M]; // 不要混用!!! 14 int head[N],dfn[N],low[N],st[N],bel[N],h[N]; 15 int ru[N],q[1000000],L,R,w[N],sw[N],ans[N]; 16 bool vis[N]; 17 int cnt,tn,tot,top,tot1; 18 19 inline char nc() { 20 static char buf[100000],*p1 = buf,*p2 = buf; 21
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2) ? EOF : *p1++; 22 } 23 inline int read() { 24 int x = 0,f = 1;char ch = nc(); 25 for (; ch<0||ch>9; ch = nc()) 26 if (ch==-) f = -1; 27 for (; ch>=0&&ch<=9; ch = nc()) 28 x = x*10+ch-0; 29 return x * f; 30 } 31 32 inline void add_edge(int u,int v) { 33 e[++tot].to = v,e[tot].nxt = head[u],head[u] = tot; 34 } 35 inline void add(int u,int v) { 36 s[++tot1].to = v,s[tot1].nxt = h[u],h[u] = tot1; // 不要寫成e 37 } 38 void tarjan(int u) { 39 dfn[u] = low[u] = ++tn; 40 st[++top] = u; 41 vis[u] = true; 42 for (int i=head[u]; i; i=e[i].nxt) { 43 int v = e[i].to; 44 if (!dfn[v]) { 45 tarjan(v); 46 low[u] = min(low[u],low[v]); 47 } 48 else if (vis[v]) 49 low[u] = min(low[u],dfn[v]); 50 } 51 if (low[u]==dfn[u]) { 52 ++cnt; 53 do { 54 vis[st[top]] = false; 55 bel[st[top]] = cnt; 56 sw[cnt] += w[st[top]]; 57 top--; 58 } while (st[top+1] != u); 59 } 60 } 61 62 int main() { 63 64 int n = read(),m = read(); 65 for (int i=1; i<=n; ++i) 66 w[i] = read(); 67 for (int i=1; i<=m; ++i) { 68 add_edge(read(),read()); 69 } 70 for (int i=1; i<=n; ++i) 71 if (!dfn[i]) tarjan(i); 72 for (int u=1; u<=n; ++u) { 73 for (int i=head[u]; i; i=e[i].nxt) { 74 int v = e[i].to; 75 if (bel[u]!=bel[v]) 76 add(bel[u],bel[v]),ru[bel[v]]++; 77 } 78 } 79 L = 1,R = 0; 80 for (int i=1; i<=cnt; ++i) { 81 if (!ru[i]) q[++R] = i,ans[i] = sw[i]; 82 } 83 84 while (L <= R) { 85 int u = q[L++]; 86 for (int i=h[u]; i; i=s[i].nxt) { 87 int v = s[i].to; 88 ans[v] = max(ans[u]+sw[v],ans[v]); 89 ru[v] --; 90 if (ru[v]==0) q[++R] = v; // 拓撲!!!不是bfs 91 92 } 93 } 94 int mx = 0; 95 for (int i=1; i<=cnt; ++i) { 96 mx = max(mx,ans[i]); 97 } 98 printf("%d",mx); 99 return 0; 100 }

P3387 【模板】縮點