题目大意:给你一个有向图,让你找一条路径,使得该路径点权之和最大,如果重复经过只算一次。问最大是多少?
解题思路:对每个强连通分量,如果到了某一个点,必然要把这里的所有点走一遍,和才会最大(废话)。
于是我们缩点。
然后暴力、拓扑+DP貌似都行。
然后我Tarjan+暴力就过了(暴力出奇迹~(≧▽≦)/~)
C++ Code:
#include<cstdio> #include<cstring> #include<cctype> #include<vector> #define N 100005 #define reg register using namespace std; struct edge{ int from,to,nxt; }e[10*N<<1]; int head[N],n,m,low[N],dfn[N],cnt,stack[N],top,ltfl,ys[N],ans,f[N],a[N]; bool vis[N]; vector<int>v[N]; inline int readint(){ char c=getchar(); bool b=false; for(;!isdigit(c);c=getchar())b=c=='-'; int d=0; for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return b?-d:d; } inline int min(int a,int b){return a<b?a:b;} inline int max(int a,int b){return a>b?a:b;} void tarjan(int now){ dfn[now]=low[now]=++cnt; vis[stack[++top]=now]=true; for(reg int i=head[now];i;i=e[i].nxt) if(!dfn[e[i].to]){ tarjan(e[i].to); low[now]=min(low[now],low[e[i].to]); }else if(vis[e[i].to])low[now]=min(low[now],dfn[e[i].to]); if(low[now]==dfn[now]){ int v; f[++ltfl]=0; do{ v=stack[top--]; ::v[ltfl].push_back(v); ys[v]=ltfl; vis[v]=false; f[ltfl]+=a[v]; }while(v!=now); } } void dfs(int now,int s){ vis[now]=true; for(reg int i=v[now].size()-1;i>=0;--i){ for(reg int j=head[v[now][i]];j;j=e[j].nxt) if(!vis[ys[e[j].to]])dfs(ys[e[j].to],s+f[ys[e[j].to]]); } vis[now]=false; ans=max(ans,s); } int main(){ ltfl=0; memset(head,0,sizeof head); n=readint(),m=readint(); for(reg int i=1;i<=n;++i)a[i]=readint(); for(reg int i=1;i<=m;++i){ int u=readint(),v=readint(); e[i]=(edge){u,v,head[u]}; head[u]=i; } memset(vis,0,sizeof vis); top=0; memset(low,0,sizeof low); memset(dfn,0,sizeof dfn); for(reg int i=1;i<=n;++i) if(!dfn[i]){ tarjan(i); } memset(vis,0,sizeof vis); ans=0; for(reg int i=1;i<=ltfl;++i) dfs(i,f[i]); printf("%d ",ans); return 0; }