zoukankan      html  css  js  c++  java
  • BZOJ4016 最短路径树问题

      给一个包含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的路径。
      2016.12.7新加数据一组by - wyx-150137

    题解

    首先我们先建立最短路径树(dijkstra+dfs),让后对最短路径树做点分治,f[i][j][2]:表示前i个子树到根节点距离为j  {0:表示最大距离   1:表示当前最大距离的路径数}
    对与新加的子树,做一边相同操作后,更新f即可.

    参考代码

    #include<bits/stdc++.h>
    using namespace std;
    #define PI acos(-1.0)
    #define pii pair<int,int>
    #define mkp make_pair
    typedef long long ll;
    const int INF=0x3f3f3f3f;
    const int maxn=60010;
    
    int n,m,k;
    vector<pii> v[maxn];
    int head[maxn],h[maxn],vis[maxn],fa[maxn],cnt1,cnt;
    int f[maxn][2],g[maxn][2];
    int dis[maxn],deep[maxn];
    int rt,sum,S,mx[maxn],size[maxn];
    int ans1,ans2;
    
    struct Edge{
        int v,w,nxt;
    } edge[maxn<<1],e[maxn<<1];
    
    void addedge(int u,int v,int w)
    {
        edge[cnt].v=v;
        edge[cnt].w=w;
        edge[cnt].nxt=head[u];
        head[u]=cnt++;
    }
    
    void addedge1(int u,int v,int w)
    {
        e[cnt1].v=v;
        e[cnt1].w=w;
        e[cnt1].nxt=h[u];
        h[u]=cnt1++;
    }
    
    void dijkstra()
    {
        priority_queue<pii,vector<pii>,greater<pii> > q;
        q.push(make_pair(0,1));
        for(int i=2;i<=n;++i) dis[i]=INF;
        dis[1]=0;
        while(!q.empty())
        {
            int u=q.top().second; 
            int x=q.top().first;q.pop();
            if(dis[u]!=x) continue;
            for(int i=head[u];~i;i=edge[i].nxt)
            {
                int V=edge[i].v;
                if(dis[u]+edge[i].w<dis[V])
                {
                    dis[V]=dis[u]+edge[i].w;
                    q.push(make_pair(dis[V],V));
                }
            }
        }
        
    }
    
    void dfs(int u)
    {
        vis[u]=1;
        for(int i=head[u];~i;i=edge[i].nxt)
        {
            int v=edge[i].v;
            if(!vis[v] && dis[u]+edge[i].w==dis[v])
            {
                addedge1(u,v,edge[i].w);
                addedge1(v,u,edge[i].w);
                dfs(v);
            }
        }
    }
    
    void getroot(int u)
    {
        size[u]=1;mx[u]=0;
        for(int i=h[u];~i;i=e[i].nxt)
        {
            int v=e[i].v;
            if(v!=fa[u] && !vis[v])
            {
                fa[v]=u;
                getroot(v);
                mx[u]=max(mx[u],size[v]);
                size[u]+=size[v];
            }
        }
        mx[u]=max(mx[u],sum-size[u]);
        if(mx[u]<mx[rt]) rt=u;
    }
    
    void solve(int x,int S)
    {
        vis[x]=1; f[0][1]=1;
        
        for(int i=h[x];~i;i=e[i].nxt)
        {
            if(!vis[e[i].v])
            {
                int hed=0,tail=0,q[maxn];
                q[tail++]=e[i].v;
                fa[e[i].v]=x;
                dis[e[i].v]=e[i].w;
                deep[e[i].v]=1;
                
                while(hed!=tail)
                {
                    int now=q[hed++];
                    int K=deep[now];
                    if(K>k) break;
                    if(dis[now]>g[K][0]) g[K][0]=dis[now],g[K][1]=0;
                    if(dis[now]==g[K][0]) g[K][1]++;
                    
                    for(int j=h[now];~j;j=e[j].nxt)
                    {
                        int v=e[j].v;
                        if(!vis[e[j].v] && e[j].v!=fa[now])
                        {    
                            fa[v]=now;
                            deep[v]=deep[now]+1;
                            dis[v]=dis[now]+e[j].w;
                            q[tail++]=v;
                        }
                    }
                }
                
                for(int j=1;j<=k;++j) 
                {
                    if(g[j][0]+f[k-j][0]>ans1) ans1=g[j][0]+f[k-j][0],ans2=0;
                    if(g[j][0]+f[k-j][0]==ans1) ans2+=g[j][1]*f[k-j][1];
                }
    
                for(int j=1;j<=k;++j) 
                {
                    if(g[j][0]>f[j][0]) f[j][0]=g[j][0],f[j][1]=0;
                    if(g[j][0]==f[j][0]) f[j][1]+=g[j][1];
                    g[j][0]=g[j][1]=0;
                }
            }
        }
        
        for(int j=0;j<=k;++j) f[j][0]=f[j][1]=0;
        
        for(int j=h[x];~j;j=e[j].nxt)
        {
            if(!vis[e[j].v])
            {
                sum=size[e[j].v];
                if(size[e[j].v]>size[x]) sum=S-size[x];
                rt=0;
                if(sum>=k) getroot(e[j].v);
                solve(rt,size[e[j].v]);
            }
        }
    }
    
    int main()
    {
        scanf("%d%d%d",&n,&m,&k);
        int x,y,z;k--;
        for(int i=1;i<=m;++i)
        {
            scanf("%d%d%d",&x,&y,&z);
            v[x].push_back(make_pair(y,z));
            v[y].push_back(make_pair(x,z));
        }
        
        cnt=cnt1=ans1=0;
        memset(head,-1,sizeof(head));
        memset(h,-1,sizeof(h));
        memset(vis,0,sizeof(vis));
        
        for(int i=1;i<=n;++i)
        {
            sort(v[i].begin(),v[i].end());
            for(int j=v[i].size()-1;j>=0;--j)
                addedge(i,v[i][j].first,v[i][j].second);
        }
        
        dijkstra();
        dfs(1);
        
        memset(vis,0,sizeof(vis));
        rt=0;mx[0]=INF;sum=n;
        getroot(1);
        solve(rt,sum);
        
        printf("%d %d
    ",ans1,ans2);
        
        return 0;
    }
    View Code
     
  • 相关阅读:
    koa学习中的一系列问题-mongodb
    JS基础语法使用
    vue中的this指向问题
    CDN的问题
    vue基本语法及使用
    python自动化读取excel数据,写入excel数据,xlrd、xlutils
    jenkins配置邮件发送功能
    pytest生成的index.html报告发送邮箱后没有样式的解决办法
    pytest命令同时执行多个目录,多个不同目录下的文件
    pytest+jenkins+allure生成报告
  • 原文地址:https://www.cnblogs.com/csushl/p/10923593.html
Copyright © 2011-2022 走看看