题目:缩点
思路:
首先先跑一边tarjan缩个点。
后面的最长路部分,第一次写时用了个dijkstra,这次用的记忆化搜索。
tarjan时要注意判断找到的pre不为0的点是不是祖先,只有当这个点没被染色时才算找到反向边。
还有记忆化的转移方程不能写错啊……
代码:
#include<bits/stdc++.h>
using namespace std;
#define maxn 10000
#define read(x) scanf("%d",&x)
int n,m;
vector<int> g[maxn+5];
int w[maxn+5];
int pre[maxn+5],low[maxn+5],cnt;
stack<int> stk;
vector<int> col[maxn+5];
int col2[maxn+5];
int num;
vector<int> a[maxn+5];
int v[maxn+5];
int d[maxn+5];
int du[maxn+5];
void readin() {
read(n),read(m);
for(int i=1;i<=n;i++) {
read(w[i]);
}
for(int i=1;i<=m;i++) {
int x,y;
read(x),read(y);
g[x].push_back(y);
}
}
void tarjan(int x,int fa) {
pre[x]=low[x]=++cnt;
stk.push(x);
for(int i=0;i<g[x].size();i++) {
int y=g[x][i];
if(!pre[y]) {
tarjan(y,x);
low[x]=min(low[x],low[y]);
} else if(!col2[y]) low[x]=min(low[x],pre[y]);
}
if(low[x]==pre[x]) {
int u;
++num;
do{
u=stk.top();
stk.pop();
col2[u]=num;
col[num].push_back(u);
} while(u!=x);
}
}
map< pair<int,int> ,int> mp;
void make_g() {
for(int i=1;i<=num;i++) {
for(int j=0;j<col[i].size();j++) {
int x=col[i][j];
v[i]+=w[x];
for(int k=0;k<g[x].size();k++) {
int y=col2[g[x][k]];
if(y!=i&&!mp.count(make_pair(i,y))) a[i].push_back(y),mp[make_pair(i,y)]=true,du[y]++;
}
}
}
}
int dfs(int x,int fa) {
if(d[x]) return d[x];
for(int i=0;i<a[x].size();i++) {
int y=a[x][i];
d[x]=max(dfs(y,x),d[x]);
}
d[x]+=v[x];
return d[x];
}
int main() {
readin();
for(int i=1;i<=n;i++) if(!pre[i]) tarjan(i,0);
make_g();
int ans=0;
for(int i=1;i<=num;i++) {
if((!du[i])&&!d[i]) ans=max(ans,dfs(i,0));
}
printf("%d",ans);
return 0;
}