-
P3387 【模板】缩点
- 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。
- 允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。
-
#include<bits/stdc++.h> using namespace std; #define maxn 12345 int head[maxn],tme,n,m,w[maxn]; int low[maxn],dfn[maxn],stk[maxn]; int top,cnt,x,y,numm; int dp[maxn],in[maxn],fa[maxn],ans; bool instack[maxn]; struct node { int v,to; } edge[maxn*10]; struct edg { int x,y; } daa[maxn*10]; void add(int u,int v) { edge[++cnt].to=head[u]; edge[cnt].v=v; head[u]=cnt; } void tarjan(int u) { int v; low[u]=dfn[u]=++tme; stk[top++]=u; instack[u]=1; for(int i=head[u]; i!=-1; i=edge[i].to) { v=edge[i].v; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } if(instack[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { cnt++; do { v=stk[--top]; fa[v]=u; instack[v]=0; if(u!=v) w[u]+=w[v]; } while(u!=v); } } void topo() { queue<int>q; for(int i=1; i<=n; i++) { if(fa[i]==i&&!in[i]) { q.push(i); dp[i]=w[i]; } } while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u]; i!=-1; i=edge[i].to) { int v=edge[i].v; dp[v]=max(dp[v],dp[u]+w[v]); in[v]--; if(in[v]==0)q.push(v); } } for(int i=1; i<=n; i++) ans=max(ans,dp[i]); printf("%d\n",ans); } void solve() { for(int i=1; i<=n; i++) if(!dfn[i])tarjan(i); cnt=0; memset(head,-1,sizeof(head)); for(int i=0; i<m; i++) { if(fa[daa[i].x]==fa[daa[i].y])continue; add(fa[daa[i].x],fa[daa[i].y]); in[fa[daa[i].y]]++; } topo(); } int main() { memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) { scanf("%d",&w[i]); fa[i]=i; } for(int i=0; i<m; i++) { scanf("%d%d",&x,&y); add(x,y); daa[i].x=x; daa[i].y=y; } solve(); return 0; }
P3387 -缩点-DAGdp
猜你喜欢
转载自blog.csdn.net/BePosit/article/details/84846716
今日推荐
周排行