CF459E Pashmak and Graph

给一个带权有向图,求其中严格递增的最长路径的长度(算边数)。

分析:第一眼想到的肯定是dp,令f[i]表示以结点i结尾的最长路径长度,但是发现有后效性,没办法滴出答案。可以先对边权从小到大进行排序,然后扫描边,这样可以不用考虑边权之间的约束关系。假设扫描到一条边e[i],从u指向v,那么可以直接更新f[v] = max(f[u]+1, f[v]),为什么可以直接更新呢?因为f[u]是由e[i]前面那些边权小于e[i]的边构成的,不用考虑边权的约束。
但是这样最后求出来的答案不是严格递增的,我们还需要考虑那些边权相同的边带来的相互影响。我们可以对边权相同的边一起考虑,假设e[i]到e[j]的边权相同,现在一次扫描这些边,把需要更新的f[i]先存到g[i]里面,等这些边权相同的边全部考虑完之后,再把g[]里的值赋给f[]。这样就行了。

#include <cstdio>
#include <algorithm>

using namespace std;
const int maxn = 3e5+5;
struct edge{
    int u, v, w;
    friend bool operator < (const struct edge &a, const struct edge &b){
        return a.w < b.w;
    }
}e[maxn];
int n, m;
int f[maxn], g[maxn];          // f[v] = max(f[v], f[u]+1)
int sta[maxn], top;
inline int read(){
    int x=0; char ch = getchar();
    while (ch<'0' || ch>'9')    ch = getchar();
    while (ch>='0' && ch<='9'){
        x = x*10 + ch-'0';
        ch = getchar();
    }
    return x;
}
int main(){
    int ans = 0;
    n = read(), m = read();
    for (int i=1; i<=m; i++)    e[i].u = read(), e[i].v = read(), e[i].w = read();
    sort (e+1, e+m+1);
    top = 0;
    for (int i=1; i<=m; ){
        int j = i;
        while (e[i].w == e[j+1].w)  j++;
        for (int k=i; k<=j; k++)    if (f[e[k].u]+1 > f[e[k].v]){
            g[e[k].v] = max (f[e[k].u] + 1, g[e[k].v]);
            sta[++top] = e[k].v;
        }
        while (top){
            f[sta[top]] = max(f[sta[top]], g[sta[top]]);
            g[sta[top]] = 0;
            top--;
        }
        i = j+1;
    }
    for (int i=1; i<=n; i++)    ans = max(ans, f[i]);
    printf ("%d", ans);
    return 0;
}
分类: 杂题

0 条评论

发表评论

邮箱地址不会被公开。