[SDOI 2010]魔法猪学院

Description

题库链接

给出一张 $n$ 个点 $m$ 条边有向图,询问最多有多少条不同的路径从 $1$ 到 $n$ 并且路径长度和 $\leq E$ 。

$2\leq n\leq 5000,1\leq m\leq 200000,1\leq E\leq 10^7$

Solution

由于要求最多多少条,我们有贪心的思想,选取尽可能短的路径不会差。

那么题目就变成了求这张图 $1\rightarrow n$ 的最短的 $ans$ 条路径,并且路径的长度和 $\leq E$ 。

就变成了裸的 $k$ 短路问题。

由 $f(x)=g(x)+h(x)$ ,由于让路径尽可能短,那么估价函数 $h(x)$ 就取点 $x$ 到 $n$ 的最短路就好了。

b站上这道题代码写的丑的 $stl$ 会 $MLE$ ,像我这种菜鸡肯定过不了,只能手写可并堆了...

Code

//It is made by Awson on 2018.3.1
#include <bits/stdc++.h>
#define LL long long
#define dob complex<double>
#define Abs(a) ((a) < 0 ? (-(a)) : (a))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
#define writeln(x) (write(x), putchar('\n'))
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int N = 5000, M = 200000, INF = ~0u>>1;
void read(int &x) {
    char ch; bool flag = 0;
    for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
    for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
    x *= 1-2*flag;
}
void print(int x) {if (x > 9) print(x/10); putchar(x%10+48); }
void write(int x) {if (x < 0) putchar('-'); print(Abs(x)); }

int n, m, vis[N+5]; double dist[N+5], e;
struct node {
    double f, g; int u;
    bool operator < (const node &b) const {return f > b.f; }
};
struct mergeable_tree {
    int ch[1300005][2], dist[1300005], pos, root, cnt; node k[1300005];
    queue<int>mem;
    int newnode(node x) {
    int o; if (!mem.empty()) o = mem.front(), mem.pop(); else o = ++pos;
    ch[o][0] = ch[o][1] = dist[o] = 0; k[o] = x; return o;
    }
    int merge(int a, int b) {
    if (!a || !b) return a+b;
    if (k[a] < k[b]) Swap(a, b);
    ch[a][1] = merge(ch[a][1], b);
    if (dist[ch[a][0]] < dist[ch[a][1]]) Swap(ch[a][0], ch[a][1]);
    dist[a] = dist[ch[a][1]]+1; return a;
    }
    node top() {return k[root]; }
    void push(node x) {root = merge(root, newnode(x)); ++cnt; }
    void pop() {mem.push(root); root = merge(ch[root][0], ch[root][1]); --cnt; }
    bool empty() {return !cnt; }
}Q;
struct Graph {
    struct tt {int to, next; double cost; }edge[M+5];
    int path[N+5], top;
    void add(int u, int v, double c) {edge[++top].to = v, edge[top].next = path[u], edge[top].cost = c, path[u] = top; }
    void SPFA() {
    for (int i = 1; i < n; i++) dist[i] = INF;
    queue<int>Q; vis[n] = 1; Q.push(n);
    while (!Q.empty()) {
        int u = Q.front(); Q.pop(); vis[u] = 0;
        for (int i = path[u]; i; i = edge[i].next)
        if (dist[edge[i].to] > dist[u]+edge[i].cost) {
            dist[edge[i].to] = dist[u]+edge[i].cost;
            if (!vis[edge[i].to]) Q.push(edge[i].to), vis[edge[i].to] = 1;
        }
    }
    }
    int Astar() {
    int ans = 0;
    node t, tt; t.f = dist[1], t.g = 0, t.u = 1;
    Q.push(t);
    while (!Q.empty()) {
        t = Q.top(); Q.pop();
        if (t.u == n) {if (e >= t.f) {ans++, e -= t.f; continue; } else break; }
        for (int i = path[t.u]; i; i = edge[i].next) {
        tt.g = t.g+edge[i].cost, tt.u = edge[i].to, tt.f = tt.g+dist[edge[i].to];
        Q.push(tt);
        }
    }
    return ans;
    }
}g1, g2;

void work() {
    read(n), read(m); scanf("%lf", &e); int u, v; double c;
    for (int i = 1; i <= m; i++) {
    read(u), read(v), scanf("%lf", &c), g1.add(u, v, c), g2.add(v, u, c);
    }
    g2.SPFA(); writeln(g1.Astar());
}
int main() {
    work(); return 0;
}
posted @ 2018-03-01 08:30  NaVi_Awson  阅读(130)  评论(0编辑  收藏  举报