题目链接:http://poj.org/problem?id=3249
题意是给了n个点,m条边(单向边),然后每个点都有一个点权(存在负权),问从入度为0的点开始到出度为0的点,最大的权值和为多少。
题目中说了这是一个DAG图(有向无环图),跑最长路的话会超时(spfa反向建边好像可以过),根据有向无环图的性质我们可以用拓扑排序来写,根据每条边的度数来选择边的顺序从而更新最长路的值。
AC代码:
// #include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define maxn 100005
#define maxm 1000005
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
struct Node{
int to,next;
}Edge[maxm];
int head[maxn],num;
int n,m;
int depi[maxn], pre[maxn], depo[maxn];
ll dist[maxn];
void init(){
for(int i=0;i<=n;i++){
depi[i] = depo[i] = 0;
head[i] = -1;
dist[i] = -inf;
}
num = 0;
}
void add(int u,int v){
Edge[num].to = v;
Edge[num].next = head[u];
head[u] = num ++;
}
void Topo(){
queue<int> q;
for(int i=1;i<=n;i++){
if(depi[i] == 0){
q.push(i);
dist[i] = pre[i];
}
}
while(!q.empty()){
int u = q.front();
q.pop();
for(int i=head[u];i!=-1;i=Edge[i].next){
int v = Edge[i].to;
dist[v] = max(dist[v], dist[u] + pre[v]);
if(--depi[v] == 0) q.push(v);
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m)){
init();
for(int i=1;i<=n;i++){
scanf("%d",&pre[i]);
}
for(int i=0;i<m;i++){
int u, v;
scanf("%d%d",&u, &v);
add(u, v);
depi[v] ++;
depo[u] ++;
}
Topo();
ll ans = -inf;
for(int i=1;i<=n;i++){
if(depo[i] == 0) ans = max(ans, dist[i]);
}
printf("%lld\n", ans);
}
return 0;
}