P3627 [APIO2009]抢掠计划
Description:
Siruseri 城中的道路都是单向的。不同的道路由路口连接。按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机。令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧。Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫。他将从市中心 出发,沿着单向道路行驶,抢劫所有他途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利。使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的现金数额。他希 望你帮助他计算从市中心出发最后到达某个酒吧时最多能抢劫的现金总数。他可 以经过同一路口或道路任意多次。但只要他抢劫过某个 ATM 机后,该 ATM 机 里面就不会再有钱了。 例如,假设该城中有 6 个路口,道路的连接情况如下图所示:
市中心在路口 1,由一个入口符号→来标识,那些有酒吧的路口用双圈来表示。每个 ATM 机中可取的钱数标在了路口的上方。在这个例子中,Banditji 能抢 劫的现金总数为 47,实施的抢劫路线是:1-2-4-1-2-3-5。
Analysis:
tarjan缩点建新图,在新图上SPFA跑最长点权路。
Code
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define M 500001 #define N 500001 using namespace std; struct edge{ int u,v,next; }e[M],rE[M]; int head[N],st[N],scc[N],dfn[N],low[N],top,num_dfs,num_scc,num_edge1,num_edge2,n,m,S,P; int vis[N],w[N],W[N],pub[N],dp[N],x[N],y[N]; inline void add(int u,int v,edge E[],int & num){ E[++num].next = head[u]; E[num].u = u; E[num].v = v; head[u] = num; } bool cmp(edge & a,edge &b){ if(a.u == b.u) return a.v < b.v; return a.u < b.u; } void SPFA(){ queue<int> Q; Q.push(S); dp[S] = W[S]; vis[S] = 1; while(!Q.empty()){ int u = Q.front();Q.pop(); vis[u] = 0; for(int i = head[u];i;i = rE[i].next){ int v = rE[i].v; if(dp[v] < dp[u] + W[v]){ dp[v] = dp[u] + W[v]; if(!vis[v]){ Q.push(v); vis[v] = 1; } } } } } void tarjan(int u){ dfn[u] = low[u] = ++num_dfs; st[++top] = u; 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(!scc[v]) low[u] = min(low[u],dfn[v]); } } if(low[u] == dfn[u]){ ++num_scc; scc[u] = num_scc; W[num_scc] += w[u]; while(st[top] != u){ scc[st[top]] = num_scc; W[num_scc] += w[st[top]]; --top; } --top; } } void solve(){ for(int i = 1;i <= n;++i){ if(!dfn[i]) tarjan(i); } memset(head,0,sizeof(head)); //newGraph for(int i = 1;i <= m;++i){ if(scc[x[i]] != scc[y[i]]){ add(scc[x[i]],scc[y[i]],rE,num_edge2); } } //sort(rE+1,rE+1+num_edge2,cmp); S = scc[S]; SPFA(); int ans = 0; for(int i = 1;i <= P;++i){ ans = max(ans,dp[scc[pub[i]]]); } printf("%d\n",ans); } int main(){ scanf("%d %d",&n,&m); for(int i = 1;i <= m;++i){ scanf("%d %d",&x[i],&y[i]); add(x[i],y[i],e,num_edge1); } for(int i = 1;i <= n;++i){ scanf("%d",&w[i]); } scanf("%d%d",&S,&P); for(int i = 1;i <= P;++i){ scanf("%d",&pub[i]); } solve(); return 0; }
岂能尽如人意,但求无愧我心
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Sdcb Chats 技术博客:数据库 ID 选型的曲折之路 - 从 Guid 到自增 ID,再到
· 语音处理 开源项目 EchoSharp
· 《HelloGitHub》第 106 期
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 使用 Dify + LLM 构建精确任务处理应用