DAG 图上的最长路问题 (兼模板)

DAG图上可以做很多问题, 最常见的就是转化为求最长路问题. 那么求DAG上的最长路有很多方法, 其中所有的方法都离不开dp的思想, 只是用来求该dp的方式不同而已. 有拓扑序, DFS, BFS等. 最长路的模型也因为是点权还是边权有着不同, 注意写法就是了.
因为做过的一些题, 对于我来说有以下模板:
1: 常规的求某次最长路.
推荐用BFS. 优点是好写, 方便记路径等. 此时dp[i] 代表的是从起点到该点 i 的最优值.
板子:

struct node {
    int to,next,w;
}e[maxn];
int cnt, head[maxn];
void init() {
    Fill(head, -1);
    cnt = 0;
}
void add(int u,int v,int w) {
    e[cnt] = (node){v, head[u], w};
    head[u] = cnt++;
}
void solve() {
    queue<int>q; q.push(1);
    while(!q.empty()) {
        int u = q.front();
        q.pop();

        for(int i = head[u] ; ~i ; i = e[i].next){
            int v = e[i].to;
            int w = e[i].w + dp[u];
            if(dp[v] < w){
                dp[v] = w; // 记录路径可以在这里面加就行.
                if(dp[v] > maxx) maxx = dp[v];
                q.push(v);
            }
        }
    }
    printf("%d\n", maxx);
}

模板题

2: 用于求多次最长路的即可以从任意点出发到任意点结束的那种.
(即你要for一遍以每个点为起点做一次DAG的最长路的)
此时如果还是用bfs, 复杂度是O(n*(n+m))的. 不是很优秀, 所以我们用dfs, 此时的dp[i]代表的是从该条路径的叶子结点到 i 这个点的最优值, 所以如果某次遍历到某个点时其dp有值那么, 那么就可以不用更新下去了, 因为此时的值已经是最优的了. 相当于记忆化, 这样的复杂度为O(n+m).
板子如下:

const int maxn = 1e3+5;
int n, m, cas = 1;
int dp[maxn];
struct node {
    int to, next, w;
}e[maxn*maxn];
int cnt, head[maxn];
void init() {
    Fill(head, -1);
    cnt = 0;
}
void add(int u,int v,int w) {
    e[cnt] = (node){v, head[u], w};
    head[u] = cnt++;
}
int dfs(int u) {  // 这一段是主要部分.
    if (dp[u] > 0) return dp[u]; // 记忆化.
    for (int i = head[u] ; ~i ; i = e[i].next) {
        dp[u] = max(dp[u], dfs(e[i].to) + e[i].w);
    }
    return dp[u];
}
void solve() {
    scanf("%d%d", &n, &m);
    init(); Fill(dp, 0);
    for (int i = 1 ; i <= m ; i ++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        add(u, v, w);
    }
    for (int i = 0 ; i < n ; i ++) {
        dfs(i);
    }
    int ans = 0;
    for (int i = 0 ; i < n ; i ++) {
        ans = max(ans, dp[i]);
    }
    printf("%d\n", ans);
}

测试题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值