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

    4016: [FJOI2014]最短路径树问题

    Time Limit: 5 Sec  Memory Limit: 512 MB
    Submit: 845  Solved: 309
    [Submit][Status][Discuss]

    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行,每行三个正整数Ai,Bi,Ci(1<=Ai,Bi<=n,1<=Ci<=10000),表示Ai和Bi间有一条长度为Ci的边。数据保证输入的是连通的无向图。
     

     

    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<=30000,m<=60000,2<=K<=n。数据保证最短路径树上至少存在一条长度为K的路径。


     

     

     

    Source

     

    [Submit][Status][Discuss]

    解析:

    先用dijkstra跑出最短路网,然后在最短路网上对于每个节点按照孩子编号从小到大跑dfs,就可以得到题意描述中的那棵树。 
    对于这棵树,定义状态f[i][j]表示从i号点出发经过j个点的最长路径长度,g[i][j]表示最长路径的数量。
    转移,分为子数内和跨越子数转移。 
    优化:在一棵子数内,一条路径只能是向下延伸或跨越2个子树,对于前者dfs解决,对于后者,这显然是一个可以分治的问题,用点分治可以把复杂度降到O(nlogn)即可。

    AC代码:

    //调了3个小时,不缩行了,直接扔这了 
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #define pir pair<int,int>
    using namespace std;
    const int N=1e5+10;
    vector<pir>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 add(a,b,c) (to[++totE] = b, nxt[totE] = head[a], W[totE] = c, head[a] = totE)
    int d[N]; 
    void dijkstra(){
        priority_queue<pir,vector<pir>,greater<pir> >q;
        memset(d,127,sizeof d);
        q.push(make_pair(d[1]=0,1));
        int p,dis,w,v;
        while(!q.empty()){
            pir h=q.top();q.pop();
            dis=h.first;
            p=h.second;
            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)){
                    q.push(make_pair(d[v]=dis+w,v)); 
                }
            }
        }
    }
    void Build(int u){
        int v;
        vis[u]=1;
        for(int i=0;i<G[u].size();i++){
            if(!vis[v=G[u][i].first]&&d[v]==d[u]+G[u][i].second){
                add(v,u,G[u][i].second);
                add(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]=1;
        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;
        for(int a,b,c,i=1;i<=m;i++){
            scanf("%d%d%d",&a,&b,&c);
            G[a].push_back(make_pair(b,c)); 
            G[b].push_back(make_pair(a,c)); 
        }
        dijkstra();
        Build(1);
        memset(vis,0,sizeof vis);
        froot=siz=n;
        getroot(1,root=0);
        solve(root,n);
        printf("%d %d
    ",mv,cnt);
        return 0;
    } 

     

  • 相关阅读:
    华为机试题 成绩排名
    华为机试题 四则运算
    华为机试题 求最大连续bit数
    华为机试题 Redraiment
    华为机试题 素数伴侣
    华为机试题 字符串排序
    华为机试题 计算字符串的距离
    华为机试题 多线程
    UE4-快捷键-按键监听事件
    UE4-Blueprint Class-Actor-开关门-盒子触发体
  • 原文地址:https://www.cnblogs.com/shenben/p/6040689.html
Copyright © 2011-2022 走看看