码迷,mamicode.com
首页 > 其他好文 > 详细

洛谷 P3387 【模板】缩点 题解

时间:2017-10-16 12:11:22      阅读:135      评论:0      收藏:0      [点我收藏+]

标签:long   oid   正文   getch   重复   sum   输出   建图   code   

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。

题目链接:https://www.luogu.org/problem/show?pid=3387

题目背景

缩点+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

 

AC代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<queue>
  6 #include<stack>
  7 
  8 const int MAXN = 2000005;
  9 inline void read(int &x)
 10 {
 11     char ch = getchar(),c = ch;x = 0;
 12     while(ch < 0 || ch > 9) c = ch,ch = getchar();
 13     while(ch <= 9 && ch >= 0) x = (x<<1)+(x<<3)+ch-0,ch = getchar();
 14     if(c == -) x = -x;
 15 }
 16 
 17 int n,m,v,cnt,dfn_cnt,part,ans;
 18 int head[MAXN],val[MAXN],dfn[MAXN],low[MAXN];
 19 int belong[MAXN],sum[MAXN],f[MAXN],t[MAXN];
 20 int vis[MAXN],dp[MAXN];
 21 
 22 struct Edge
 23 {
 24     int f,t,nxt;
 25 }e[MAXN];
 26 
 27 void insert(int f,int t)
 28 {
 29     e[++cnt].f = f,e[cnt].t = t;
 30     e[cnt].nxt = head[f];
 31     head[f] = cnt;
 32 }
 33 
 34 inline int Min(int a,int b)
 35 {return a<b?a:b;}
 36 
 37 inline int Max(int a,int b)
 38 {return a>b?a:b;}
 39 
 40 std::stack <int> s;
 41 
 42 void tarjan(int u)
 43 {
 44     dfn[u] = low[u] = ++dfn_cnt;
 45     s.push(u);
 46     for(int i = head[u];i;i = e[i].nxt)
 47     {
 48         int v = e[i].t;
 49         if(!dfn[v]){
 50             tarjan(v);
 51             low[u] = Min(low[v],low[u]);
 52         }
 53         else if(!belong[v])
 54             low[u] = Min(low[u],dfn[v]);
 55     }
 56     if(dfn[u] == low[u])
 57     {
 58         ++ part;
 59         while(!s.empty())
 60         {
 61             int tmp = s.top();
 62             s.pop();
 63             belong[tmp] = part;
 64             sum[part] += val[tmp];
 65             if(tmp == u) break;
 66         }
 67     }
 68 }
 69 
 70 int dfs(int u)
 71 {
 72     if(dp[u]) return dp[u];
 73     dp[u] = sum[u];
 74     int mx = 0;
 75     for(int i = head[u];i;i = e[i].nxt)
 76     {
 77         int t = e[i].t;
 78         if(!dp[t]) dfs(t);
 79         if(dp[t] > mx) mx = dp[t];
 80     }
 81     dp[u] += mx;
 82     return dp[u];
 83 }
 84 
 85 int main()
 86 {
 87     read(n),read(m);
 88     for(int i = 1;i <= n;++ i)
 89         read(val[i]);
 90     for(int i = 1;i <= m;++ i)
 91     {
 92         read(f[i]),read(t[i]);
 93         insert(f[i],t[i]);
 94     }
 95     //Tarjan缩点 
 96     for(int i = 1;i <= n;++ i)
 97         if(!dfn[i])
 98             tarjan(i);
 99     memset(head,0,sizeof(head));
100     memset(vis,0,sizeof(vis));
101     memset(e,0,sizeof(e));
102     cnt = 0;
103     //重新建图 
104     for(int i = 1;i <= m;++ i)
105         if(belong[f[i]] != belong[t[i]])
106             insert(belong[f[i]],belong[t[i]]);
107     //DAG DP
108     for(int i = 1;i <= part;++ i)
109     {
110         if(!dp[i]){
111             dfs(i);
112             ans = Max(ans,dp[i]);    
113         }
114     }
115     printf("%d\n",ans);
116     return 0;
117 }

 

 

洛谷 P3387 【模板】缩点 题解

标签:long   oid   正文   getch   重复   sum   输出   建图   code   

原文地址:http://www.cnblogs.com/shingen/p/7676161.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!