2010-1112

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

题意:
给定一有向图,查询从0开始到达每一个点的最短路中经过某点x的最短路数有多少。

解法:
因为查询的是最短路,所以从0开始做最短路,即可得到一有向无环图。
题目中查询某一点x的答案相当于以该点为终点的最短路数(end[x])与以该点为起点的最短路数(begin[x])的乘积
ans[x] = end[x] * begin[x]
其中end[x]可以在求最短路的时候顺带求出。
begin[x]由于是有向无环图,所有按拓扑关系dp一下即可
begin[x] = sigma{begin[k] : dist[0][k] = dist[0][x] + edge[x][k]} + 1
其中dist[0][x]为从0到x最短路的长度
注意最后输出的是10位数,所以乘法会爆long long,需要特别处理一下

代码:
{{{
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;

typedef long long LL;

const int MAXN = 11000;
const int INF = 1000000000;
const LL MOD = 10000000000LL;

priority_queue<pair<int, int> > Q;
vector<pair<int, int> > v[MAXN], rv[MAXN];
vector<int> list;

int N, dis[MAXN];
LL begin[MAXN], end[MAXN], ans[MAXN];

void solve() {

    for (int i = 0; i < N; i++) dis[i] = INF, end[i] = 0;
    dis[0] = 0;
    end[0] = 1;
    Q.push(make_pair(0, 0));
    list.clear();
    while (!Q.empty()) {
        int cur = Q.top().second, len = -Q.top().first;
        Q.pop();
        if (dis[cur] != len) continue;
        list.push_back(cur);
        end[cur] %= MOD;
        for (int i = 0; i < (int)v[cur].size(); i++) {
            int next = v[cur][i].first, d = dis[cur] + v[cur][i].second;
            if (dis[next] > d) {
                dis[next] = d;
                end[next] = end[cur];
                Q.push(make_pair(-dis[next], next));
            }
            else if (dis[next] == d){
                end[next] += end[cur];
            }
        }   
    }
    for (int i = 0; i < N; i++) begin[i] = 1;
    for (int i = (int)list.size() - 1; i >= 0; i--) {
        int cur = list[i];
        begin[cur] %= MOD;
        for (int j = 0; j < (int)rv[cur].size(); j++) {
            if (rv[cur][j].second + dis[rv[cur][j].first] != dis[cur]) continue;
            begin[rv[cur][j].first] += begin[cur];
        }
    }

    int a[100], b[100], c[100];
    for (int t = 0; t < N; t++) {
        memset(a, 0, sizeof(a));
        memset(b, 0, sizeof(b));
        LL now = 1;
        for (int j = 0; j < 10; j++) {
            a[j] = begin[t] / now % 10;
            now *= 10;          
        }
        now = 1;
        for (int j = 0; j < 10; j++) {
            b[j] = end[t] / now % 10;
            now *= 10;
        }       
        memset(c, 0, sizeof(c));
        for (int i = 0; i < 10; i++)
            for (int j = 0; j < 10; j++) 
                c[i + j] += a[i] * b[j];
        for (int i = 0; i < 10; i++) {
            c[i + 1] += c[i] / 10;
            c[i] %= 10;
        }
        ans[t] = 0;
        now = 1;
        for (int i = 0; i < 10; i++) { 
            ans[t] += c[i] * now;
            now *= 10;
        }
    }   
}

void print(int cur) {
    LL now = 1000000000LL;
    for (int i = 0; i < 10; i++) {
        printf("%lld", ans[cur] / now % 10);
        now /= 10;
    }
    puts("");
}

int main() {

    int M, Q, a, b, c;
    while (scanf("%d %d %d", &N, &M, &Q) != EOF) {
        for (int i = 0; i < N; i++) {
            v[i].clear();
            rv[i].clear();
        }
        for (int i = 0; i < M; i++) {
            scanf("%d %d %d", &a, &b, &c);
            v[a].push_back(make_pair(b, c));
            rv[b].push_back(make_pair(a, c));
        }   
        solve();
        for (int i = 0; i < Q; i++) {
            scanf("%d", &a);
            print(a);
        }
    }
    return 0;
}
}}}

题意:

给定一有向图,查询从0开始到达每一个点的最短路中经过某点x的最短路数有多少。

解法:

因为查询的是最短路,所以从0开始做最短路,即可得到一有向无环图。

题目中查询某一点x的答案相当于以该点为终点的最短路数(end[x])与以该点为起点的最短路数(begin[x])的乘积

ans[x] = end[x] * begin[x]

其中end[x]可以在求最短路的时候顺带求出。

begin[x]由于是有向无环图,所有按拓扑关系dp一下即可

begin[x] = sigma{begin[k] : dist[0][k] = dist[0][x] + edge[x][k]} + 1

其中dist[0][x]为从0到x最短路的长度

注意最后输出的是10位数,所以乘法会爆long long,需要特别处理一下

代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
typedef long long LL;
const int MAXN = 11000;
const int INF = 1000000000;
const LL MOD = 10000000000LL;
priority_queue<pair<int, int> > Q;
vector<pair<int, int> > v[MAXN], rv[MAXN];
vector<int> list;
int N, dis[MAXN];
LL begin[MAXN], end[MAXN], ans[MAXN];
void solve() {
    for (int i = 0; i < N; i++) dis[i] = INF, end[i] = 0;
    dis[0] = 0;
    end[0] = 1;
    Q.push(make_pair(0, 0));
    list.clear();
    while (!Q.empty()) {
        int cur = Q.top().second, len = -Q.top().first;
        Q.pop();
        if (dis[cur] != len) continue;
        list.push_back(cur);
        end[cur] %= MOD;
        for (int i = 0; i < (int)v[cur].size(); i++) {
            int next = v[cur][i].first, d = dis[cur] + v[cur][i].second;
            if (dis[next] > d) {
                dis[next] = d;
                end[next] = end[cur];
                Q.push(make_pair(-dis[next], next));
            }
            else if (dis[next] == d){
                end[next] += end[cur];
            }
        }   
    }
    for (int i = 0; i < N; i++) begin[i] = 1;
    for (int i = (int)list.size() - 1; i >= 0; i--) {
        int cur = list[i];
        begin[cur] %= MOD;
        for (int j = 0; j < (int)rv[cur].size(); j++) {
            if (rv[cur][j].second + dis[rv[cur][j].first] != dis[cur]) continue;
            begin[rv[cur][j].first] += begin[cur];
        }
    }
    int a[100], b[100], c[100];
    for (int t = 0; t < N; t++) {
        memset(a, 0, sizeof(a));
        memset(b, 0, sizeof(b));
        LL now = 1;
        for (int j = 0; j < 10; j++) {
            a[j] = begin[t] / now % 10;
            now *= 10;          
        }
        now = 1;
        for (int j = 0; j < 10; j++) {
            b[j] = end[t] / now % 10;
            now *= 10;
        }       
        memset(c, 0, sizeof(c));
        for (int i = 0; i < 10; i++)
            for (int j = 0; j < 10; j++) 
                c[i + j] += a[i] * b[j];
        for (int i = 0; i < 10; i++) {
            c[i + 1] += c[i] / 10;
            c[i] %= 10;
        }
        ans[t] = 0;
        now = 1;
        for (int i = 0; i < 10; i++) { 
            ans[t] += c[i] * now;
            now *= 10;
        }
    }   
}
void print(int cur) {
    LL now = 1000000000LL;
    for (int i = 0; i < 10; i++) {
        printf("%lld", ans[cur] / now % 10);
        now /= 10;
    }
    puts("");
}
int main() {
    int M, Q, a, b, c;
    while (scanf("%d %d %d", &N, &M, &Q) != EOF) {
        for (int i = 0; i < N; i++) {
            v[i].clear();
            rv[i].clear();
        }
        for (int i = 0; i < M; i++) {
            scanf("%d %d %d", &a, &b, &c);
            v[a].push_back(make_pair(b, c));
            rv[b].push_back(make_pair(a, c));
        }   
        solve();
        for (int i = 0; i < Q; i++) {
            scanf("%d", &a);
            print(a);
        }
    }
    return 0;
}