POJ 3249 Test for Job (拓扑排序+DP)

<题目链接>

题目大意:

给定一个有向图(图不一定连通),每个点都有点权(可能为负),让你求出从源点走向汇点的路径上的最大点权和。

解题分析:
想到拓扑排序就好做了,然后在拓扑的过程中进行简单的状态转移。

#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;
}
原文地址:https://www.cnblogs.com/DWVictor/p/11342802.html