洛谷P3387 【模板】缩点

题目背景

缩点+DP

题目描述

给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。

允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。

输入输出格式

输入格式: 
第一行,n,m

第二行,n个整数,依次代表点权

第三至m+2行,每行两个整数u,v,表示u->v有一条有向边

输出格式: 
共一行,最大的点权之和。

输入输出样例

输入样例#1: 
2 2 
1 1 
1 2 
2 1 
输出样例#1: 

说明

n<=10^4,m<=10^5,点权<=1000

算法:Tarjan缩点+DAGdp 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<queue>
  6 using namespace std;
  7 long long read()
  8 {
  9     long long x=0,f=1;
 10     char ch=getchar();
 11     while(ch<'0'||ch>'9')
 12     {
 13         if(ch=='-')
 14             f=-1;
 15         ch=getchar();
 16     }
 17     while(ch>='0'&&ch<='9')
 18     {
 19         x=x*10+ch-'0';
 20         ch=getchar();
 21     }
 22     return x*f;
 23 }
 24 void write(long long x)
 25 {
 26     if(x<0)
 27     {
 28         x=-x;
 29         putchar('-');
 30     }
 31     if(x>9)
 32         write(x/10);
 33     putchar(x%10+'0');
 34 }
 35 const int maxn=10005;
 36 const int maxm=100005;
 37 struct node
 38 {
 39     int v,u,nxt;
 40 } e[maxm*50];
 41 int rudu[maxn],head[maxn],dfn[maxn],low[maxn],sta[maxn],dp[maxn],w[maxn],ww[maxn],fa[maxn];
 42 bool vis[maxn];
 43 queue<int>q;
 44 int n,m,num,top,ans,tot,cnt;
 45 void add(int u,int v)
 46 {
 47     e[++num].v=v;
 48     e[num].u=u;
 49     e[num].nxt=head[u];
 50     head[u]=num;
 51 }
 52 void tarjan(int x)
 53 {
 54     cnt++;
 55     dfn[x]=low[x]=cnt;
 56     vis[x]=1;
 57     top++;
 58     sta[top]=x;
 59     for(int i=head[x]; i; i=e[i].nxt)
 60     {
 61         int v=e[i].v;
 62         if(dfn[v]==0)
 63         {
 64             tarjan(v);
 65             low[x]=min(low[x],low[v]);
 66         }
 67         else if(vis[v])
 68             low[x]=min(low[x],low[v]);
 69     }
 70     if(low[x]==dfn[x])
 71     {
 72         tot++;
 73         while(sta[top]!=x)
 74         {
 75             fa[sta[top]]=tot;
 76             ww[tot]+=w[sta[top]];
 77             vis[sta[top]]=0;
 78             top--;
 79         }
 80         fa[sta[top]]=tot;
 81         ww[tot]+=w[sta[top]];
 82         vis[sta[top]]=0;
 83         top--;
 84     }
 85     return ;
 86 }
 87 int main()
 88 {
 89     n=read(),m=read();
 90     for(int i=1; i<=n; i++)
 91         w[i]=read();
 92     for(int i=1; i<=m; i++)
 93     {
 94         int u,v;
 95         u=read(),v=read();
 96         add(u,v);
 97     }
 98     for(int i=1; i<=n; i++)
 99         if(dfn[i]==0)
100             tarjan(i);
101     memset(head,0,sizeof head);
102     for(int i=1; i<=m; i++)
103     {
104         int u,v;
105         u=fa[e[i].u],v=fa[e[i].v];
106         if(u!=v)
107         {
108             add(u,v);
109             rudu[v]++;
110         }
111     }
112     for(int i=1; i<=tot; i++)
113     {
114         ans=max(ans,ww[i]);
115         if(rudu[i]==0)
116         {
117             q.push(i);
118             dp[i]+=ww[i];
119         }
120     }
121     while(!q.empty())
122     {
123         int now=q.front();
124         q.pop();
125         for(int i=head[now]; i; i=e[i].nxt)
126         {
127             int v=e[i].v;
128             dp[v]=max(dp[v],dp[now]+ww[v]);
129             ans=max(ans,dp[v]);
130             rudu[v]--;
131             if(rudu[v]==0)
132                 q.push(v);
133         }
134     }
135     write(ans);
136     return 0;
137 }
View Code
原文地址:https://www.cnblogs.com/liweilin/p/10147327.html