[无聊测试赛] T12 道路

by _Zhumingrui

这道题的大致题意是:根据最短路求边的拓扑图,然后求出每个边的入度。
我用 Dijkstra 求最短路,顺便建好图。之后使用 BFS 来递推拓扑条件,保存至 ans 数组。

注意事项

使用 long long,你们懂得。

这个做法需要倒序遍历边,因为只有倒序遍历能满足拓扑序。

本代码需要 (O_2) 优化 才可通过本题。

Code:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cstdlib>
using namespace std;
namespace {
constexpr const int N = 2333;
constexpr int M = 5555;
unsigned mod = 1000000007;
//vector清空边不容易,用前向星快好多
struct {
    struct {
        int v, n, w;
    }edge[M];
    int link[N], cnt;
    inline void add(const int& u, const int& v, const int& w) {
        edge[++cnt].w = w;
        edge[cnt].v = v;
        edge[cnt].n = link[u];
        link[u] = cnt;
    }
}a, b; //建两个图,一个(A)是原图,另一个(B)是DAG 
int n, m;
struct ___ {
    int w, v;
    inline bool operator <(const ___& b) const {
        return w > b.w;
    }
};
priority_queue<___> heap;
queue<int> q;
int d[N];
bool book[N];
int rrank[N];
long long dp[N], ans[M], dp1[N];
inline void dijkstra(const int& s) {
    b.cnt = 0;
    for (int i = 1; i <= n; i++) {
        d[i] = 0x3f3f3f3f;
        book[i] = false;
        dp[i] = 1;
        rrank[i] = 0;
        b.link[i] = 0;
        dp1[i] = 0;
    }
    d[s] = 0;
    dp1[s] = 1;
    heap.push({ 0,s });
    while (!heap.empty()) {
        int now = heap.top().v;
        heap.pop();
        if (book[now])continue;
        book[now] = true;
        //倒着推
        int nxt = a.link[now];
        while (nxt) {
            const int& v = a.edge[nxt].v;
            const int& val = a.edge[nxt].w;
            if (!book[v]) {
                //如果相等,加上一条
                if (d[v] == d[now] + val) {
                    b.add(v, now, nxt);
                    dp1[v] = (dp1[v] + dp1[now]) % mod;
                }
                //如果更好,就把边拆了,重新加上条
                if (d[v] > d[now] + val) {
                    b.link[v] = 0;
                    b.add(v, now, nxt);
                    dp1[v] = dp1[now];
                    d[v] = d[now] + val;
                    heap.push({ d[v], v });
                }
            }
            nxt = a.edge[nxt].n;
        }
    }
}
inline void toposort() {
    //求入度
    for (int i = 1; i <= n; i++)
        for (int p = b.link[i]; p; p = b.edge[p].n)
            rrank[b.edge[p].v]++;
    for (int i = 1; i <= n; i++)
        if (rrank[i] == 0)
            q.push(i);
    //递推
    while (!q.empty()) {
        int now = q.front();
        q.pop();
        int nxt = b.link[now];
        while (nxt) {
            const int& v = b.edge[nxt].v;
            const int& w = b.edge[nxt].w;
            dp[v] = (dp[v] + dp[now]) % mod;
            ans[w] = (ans[w] + dp[now] * dp1[v]) % mod;
            rrank[v]--;
            if (rrank[v] == 0)
                q.push(v);
            nxt = b.edge[nxt].n;
        }
    }
}
int u, v, w;
inline int get() {
    static unsigned char a;
    static char st[100], eof;
    if (a == 100 || a == 0)
        if (!eof) {
            if (fread(st, sizeof(char), 100, stdin) < 100)
                eof = 1;
            a = 0;
        }
        else {
            return -1;
        }
    return st[a++];
}
#ifdef  _DEBUG
#define get() getchar()
#endif
inline void read(int& ans) {
    ans = 0x00000000;
    char ch = get();
    while ((ch < '0') || (ch > '9'))ch = get();
    while ((ch >= '0') && (ch <= '9')) {
        ans = (ans << 3) + (ans << 1) + (ch & 15);
        ch = get();
    }
}
}
int main() {
#define int register int
read(n), read(m);
for (int i = 1; i <= m; i++) {
    read(u), read(v), read(w);
    a.add(u, v, w);
}
for (int i = 1; i <= n; i++) {
    dijkstra(i);
    toposort();
}
for (int i = 1; i <= m; i++)
    printf("%d
", ans[i]);
return 0;
#undef int
}
原文地址:https://www.cnblogs.com/DannyXu/p/12539203.html