<题目链接>
题目大意:
给定一个有向图(图不一定连通),每个点都有点权(可能为负),让你求出从源点走向汇点的路径上的最大点权和。
解题分析:
想到拓扑排序就好做了,然后在拓扑的过程中进行简单的状态转移。
#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\n", mx);
}
return 0;
}