zoukankan      html  css  js  c++  java
  • bzoj 4016: [FJOI2014]最短路径树问题

    bzoj4016 最短路路径问题

    Time Limit: 5 Sec Memory Limit: 512 MB

    Description

    给一个包含n个点,m条边的无向连通图。从顶点1出发,往其余所有点分别走一次并返回。
    往某一个点走时,选择总长度最短的路径走。若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径A为1,32,11,路径B为1,3,2,11,路径B字典序较小。注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小)。到达该点后按原路返回,然后往其他点走,直到所有点都走过。
    可以知道,经过的边会构成一棵最短路径树。请问,在这棵最短路径树上,最长的包含K个点的简单路径长度为多长?长度为该最长长度的不同路径有多少条?
    这里的简单路径是指:对于一个点最多只经过一次的路径。不同路径是指路径两端端点至少有一个不同,点A到点B的路径和点B到点A视为同一条路径。

    Input

    第一行输入三个正整数n,m,K,表示有n个点m条边,要求的路径需要经过K个点。
    接下来输入m行,每行三个正整数(A_i,B_i,C_i(1 le A_i,B_i le n,1 le C_i le 10000)),表示(A_i)(B_i)间有一条长度为(C_i)的边。数据保证输入的是连通的无向图。

    Output

    输出一行两个整数,以一个空格隔开,第一个整数表示包含K个点的路径最长为多长,第二个整数表示这样的不同的最长路径有多少条。

    Sample Input

    6 6 4

    1 2 1

    2 3 1

    3 4 1

    2 5 1

    3 6 1

    5 6 1

    Sample Output

    3 4

    HINT

    对于所有数据(n le 30000,m le 60000,2 le K le n)。数据保证最短路径树上至少存在一条长度为K的路径。

    题解

    这题很显然是一道点分治的裸题。
    我们可以定义(g[i])表示对于当前(root),深度为(i)的最大距离以及此距离方案数。
    为了求出(ans),我们再用(f[i])累积之前的(g[i]),这样,我们就可以直接点分治求出答案。

    #include <vector>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
     
    const int N = 30010;
    typedef pair<int, int>pii;
    vector<pii> G[N];
    int n, m, mv, cnt, root, Siz, K;
    int s[N], froot, f[2][N], g[2][N];
    bool vis[N];
    int to[N << 1], nxt[N << 1], head[N], W[N << 1], totE;
     
    #define Adde(a,b,c) (to[totE] = b, nxt[totE] = head[a], W[totE] = c, head[a] = totE++)
     
    //dijkstra
    priority_queue<pii, vector<pii>, greater<pii> >heap;
    int d[N];
     
    void dijkstra() {
        memset(d, 127, sizeof d);
        heap.push(make_pair(d[1] = 0, 1));
        int p, dis, w, v;
        while (!heap.empty()) {
            dis = heap.top().first, p = heap.top().second;
            heap.pop(); if (d[p] ^ dis) continue;
            sort(G[p].begin(), G[p].end());
            for (int i = 0; i < G[p].size(); ++i) 
              if (d[v = G[p][i].first] > dis + (w = G[p][i].second)) heap.push(make_pair(d[v] = dis + w, v));
        }
    }
     
    void Build(int u) {
        int v; vis[u] = true;
        for (int i = 0; i < G[u].size(); ++i)
          if (!vis[v = G[u][i].first] && d[v] == d[u] + G[u][i].second) {
              Adde(v, u, G[u][i].second); Adde(u, v, G[u][i].second); Build(v);
          }
    }
     
    void getroot(int u, int fa) {
        s[u] = 1; int mx = 0, v;
        for (int it = head[u]; ~it; it = nxt[it]) 
          if (!vis[v = to[it]] && (v ^ fa)) {
                getroot(v, u); s[u] += s[v];
                if (s[v] > mx) mx = s[v];
          }
        if (Siz - mx > mx) mx = Siz - mx;
        if (froot > mx) root = u, froot = mx; 
    }
     
    void dfs(int u, int fa, int dep) {
        if (dep > K) return; int v;
        if (d[u] > g[0][dep]) g[0][dep] = d[u], g[1][dep] = 0;
        if (d[u] >= g[0][dep]) ++g[1][dep];
        for (int i = head[u]; ~i; i = nxt[i]) 
          if (!vis[v = to[i]] && (v ^ fa)) {
              d[v] = d[u] + W[i]; dfs(v, u, dep + 1);
          }
    }
     
     
    void solve(int u, int S) {
        vis[u] = true; f[0][0] = 0; f[1][0] = 1;
        int v;
        for (int i = head[u]; ~i; i = nxt[i]) 
          if (!vis[v = to[i]]) {
                d[v] = W[i]; dfs(v, u, 1);
                for (int j = 1; j <= K; ++j) {
                    if (g[0][j] + f[0][K - j] > mv) mv = g[0][j] + f[0][K - j], cnt = 0;
                    if (g[0][j] + f[0][K - j] >=  mv) cnt += g[1][j] * f[1][K - j];
                }
                for (int j = 1; j <= K; ++j) {
                    if (g[0][j] > f[0][j]) f[0][j] = g[0][j], f[1][j] = 0;
                    if (g[0][j] >= f[0][j]) f[1][j] += g[1][j];
                    g[0][j] = g[1][j] = 0;
                }
          }
        for (int i = 0; i <= K; ++i) f[0][i] = f[1][i] = 0;
        for (int i = head[u]; ~i; i = nxt[i]) 
          if (!vis[v = to[i]]) {
              froot = Siz = s[v]; root = 0;
              getroot(v, u); 
              solve(root, s[v]);
          }
    }
     
    int main() {
        scanf("%d%d%d", &n, &m, &K);
        --K;
        int a, b, c;
        while (m--) {
            scanf("%d%d%d", &a, &b, &c);
            G[a].push_back(make_pair(b, c));
            G[b].push_back(make_pair(a, c));
        }
        dijkstra();
        memset(head, -1, sizeof head);
        Build(1);
        memset(vis, 0, sizeof vis);
        froot = Siz = n;
        getroot(1, root = 0);
        solve(root, n);
        printf("%d %d
    ", mv, cnt);
        return 0;
    }
    
  • 相关阅读:
    chrome输入框记住密码导致背景黄色的解决方案
    死活要居中(转载)
    Google HTML/CSS/JS代码风格指南
    CSS的inherit与auto使用分析
    photoshop中rgb与索引模式的区别
    placeholder调整颜色
    你应该了解的5个JavaScript调试技巧
    HTML TAG FROM MDN
    apple iphone 3gs 有锁机 刷机 越狱 解锁 全教程(报错3194,3014,1600,短信发不出去等问题可参考)
    史上最全的CSS hack方式一览
  • 原文地址:https://www.cnblogs.com/cycleke/p/5906018.html
Copyright © 2011-2022 走看看