<题目链接>
题目大意:
给定一个有向图(图不一定连通),每个点都有点权(可能为负),让你求出从源点走向汇点的路径上的最大点权和。
解题分析:
想到拓扑排序就好做了,然后在拓扑的过程中进行简单的状态转移。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <set> #include <queue> using namespace std; const int maxn = 1e5 + 7,M = 1e6 + 7; int n , m; std::vector<long long> g[maxn]; int ou[maxn],in[maxn]; long long dp[maxn],w[maxn]; struct Edge{ int to,nxt; }e[M]; int cnt,head[maxn]; inline void add(int u,int v){ e[cnt]=(Edge){ v,head[u] };head[u]=cnt++; } void init(){ cnt = 0; memset(head,-1,sizeof head); memset(dp,-0x3f,sizeof dp); memset(in,0,sizeof in); memset(ou,0,sizeof ou); } void topsort(){ queue<int> q; for(int i = 1;i <= n ;i ++){ if(!in[i]) { q.push(i); dp[i] = w[i]; } } while(!q.empty()){ int now = q.front() ; q.pop(); for(int i = head[now]; ~i; i = e[i].nxt){ int v = e[i].to; if(in[v] == 0) continue; in[v] --; dp[v] = max(dp[v],dp[now] + w[v]); if(!in[v]) q.push(v); } } } int main(int argc, char const *argv[]) { //int n , m; while(~scanf("%d %d",&n,&m)){ init(); for(int i = 1;i <= n; i ++) scanf("%lld",&w[i]); for(int i = 1;i <= m;i ++){ int u , v; scanf("%d %d",&u,&v); add(u,v); ou[u] ++; in[v] ++; } topsort(); long long mx = -1e18; for(int i= 1;i <= n; i ++){ if(!ou[i]){ mx = max(mx,dp[i]); } } printf("%lld ", mx); } return 0; }