题目链接
题意:给一个有向有环图,图上每个点有权值。找出一条路径点权值之和最大,注意每个点的权值只计算一次。
题解 :先将成环的强联通分量缩点,再用拓扑排序的顺序进行记忆化搜素就行了。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4+100;
int n,m;
struct edge{
int v,next;
}e[maxn*10];
int a[maxn],head[maxn],low[maxn],dfn[maxn],col[maxn],sum[maxn],s[maxn],vis[maxn];
int tot,cnt,colnum,idx,in[maxn],d[maxn];
void insert(int u,int v){
e[++tot].v=v;e[tot].next=head[u];head[u]=tot;
}
vector<int>g[maxn];
void tarjan(int u){
dfn[u]=low[u]=++cnt;
s[++idx]=u;
vis[u]=1;
for(int i=head[u];i;i=e[i].next){
int v = e[i].v;
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(vis[v]) low[u] = min(low[u],dfn[v]);
}
if(low[u]==dfn[u]){
colnum++;
do{
col[s[idx]]=colnum;
sum[colnum]+=a[s[idx]];
vis[s[idx--]]=0;
}while(u!=s[idx+1]);
}
}
int topu(){
queue<int>q;
for(int i=1;i<=colnum;i++)
if(!in[i]) {
q.push(i);
d[i]=sum[i];
}
while(!q.empty()){
int t = q.front();q.pop();
for(int i=0;i<g[t].size();i++){
int v = g[t][i];
d[v] = max(d[v],d[t]+sum[v]);
in[v]--;
if(!in[v]) q.push(v);
}
}
int ans = 0;
for(int i=1;i<=colnum;i++) ans = max(ans,d[i]);
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=m;i++) {
int u,v;
scanf("%d%d",&u,&v);
insert(u,v);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++){
for(int j=head[i];j;j=e[j].next){
if(col[i]!=col[e[j].v]){
g[col[i]].push_back(col[e[j].v]);
in[col[e[j].v]]++;
}
}
}
printf("%d\n",topu());
}