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;
    }
    
  • 相关阅读:
    解决ListView异步加载数据之后不能点击的问题
    android点击实现图片放大缩小 java技术博客
    关于 数据文件自增长 的一点理解
    RAC 实例不能启动 ORA1589 signalled during ALTER DATABASE OPEN
    Linux 超级用户的权利
    RAC 实例 迁移到 单实例 使用导出导入
    Shell 基本语法
    Linux 开机引导与关机过程
    RAC 实例不能启动 ORA1589 signalled during ALTER DATABASE OPEN
    Oracle RAC + Data Guard 环境搭建
  • 原文地址:https://www.cnblogs.com/cycleke/p/5906018.html
Copyright © 2011-2022 走看看