P3387 【模板】缩点

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 }

 

posted @ 2017-11-25 19:55  MJT12044  阅读(205)  评论(0编辑  收藏  举报