# Solution to the shrinking point of "Luogu P3387 [template]

## Title Source:

https://www.luogu.org/problemnew/show/P3387

## Background of topic

Shrinkage point +DP

## Title Description

Given a directed graph with n points and m edges, each point has a weight, and a path is found to maximize the sum of the weight of the points that the path passes through. You just need to find the sum of the weights.

It is allowed to pass an edge or a point multiple times. However, for a point that passes repeatedly, the weight is only calculated once.

## I / O format

Input format:

First line, n,m

The second line, n integers, represents point weight in turn

The third to m+2 lines, each line has two integers u,v, indicating that u - > V has a directed edge

Output format:

A total of one line, the largest sum of point weights.

## Example of input and output

Input example ා 1:copy

```2 2
1 1
1 2
2 1```

Output example:copy

`2`

## Explain

N < = 10 ^ 4, m < = 10 ^ 5, point weight < = 1000

Algorithm: Tarjan shrink point + DAGdp

## Solutions:

Don't talk about tarjan shrinking point. The key is to find the maximum point weight. I use the memory search, but I don't know very well. But it's finally passed under the reference of many parties. After remembering the shrinking point, the weight of each point is the sum of the point weights for the strongly connected components...

## Code:

```#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
int dfn,low,f,quan,lt,fl,rd,cd,tot,gs;
bool vis,ins,jl;
stack<int>s;
vector<int>E,E1;
int n,m;
void tarjan(int u)
{
dfn[u]=low[u]=++tot;
ins[u]=vis[u]=1;
s.push(u);
for(int i=0;i<E[u].size();i++)
{
int v=E[u][i];
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(ins[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]){
gs++;
while(1){
int now=s.top();
s.pop();
fl[gs]+=quan[now];
lt[now]=gs;
ins[now]=0;
vis[now]=0;
if(now==u)break;
}
}
}
void dp(int x){   //Memorize search on DAG / / you can also use spfa to find the longest path
if(f[x]) return ;
f[x]=fl[x];
int maxsum = 0;
for(int i=0;i<E1[x].size();i++){
if(!f[E1[x][i]]) dp(E1[x][i]);
maxsum=max(maxsum,f[E1[x][i]]);
}
f[x]+=maxsum;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>quan[i];
for(int i=1;i<=m;i++)
{
int a,b;
cin>>a>>b;
E[a].push_back(b);
}
tot=gs=0;
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i);
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<E[i].size();j++)
{
int v=E[i][j];
if(lt[i]==lt[v])continue;
E1[lt[i]].push_back(lt[v]);
cd[lt[i]]++;rd[lt[v]]++;
}
}
for(int i=1;i<=gs;i++){
if(!f[i]){
dp(i);
ans=max(ans,f[i]);
}
}
cout<<ans<<endl;
return 0;
}
```

Posted on Sun, 09 Feb 2020 10:52:39 -0500 by Mr P!nk