P3387 【模板】縮點
阿新 • • 發佈:2017-11-25
輸入輸出格式 無環 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 constint 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; 21return 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 【模板】縮點