zoukankan      html  css  js  c++  java
  • 洛谷 [FJOI2014]最短路径树问题 解题报告

    [FJOI2014]最短路径树问题

    题目描述

    给一个包含(n)个点,(m)条边的无向连通图。从顶点(1)出发,往其余所有点分别走一次并返回。

    往某一个点走时,选择总长度最短的路径走。若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径(A)(1,32,11),路径(B)(1,3,2,11),路径(B)字典序较小。注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小)。到达该点后按原路返回,然后往其他点走,直到所有点都走过。

    可以知道,经过的边会构成一棵最短路径树。请问,在这棵最短路径树上,最长的包含(K)个点的简单路径长度为多长?长度为该最长长度的不同路径有多少条?

    这里的简单路径是指:对于一个点最多只经过一次的路径。不同路径是指路径两端端点至少有一个不同,点(A)到点(B)的路径和点(B)到点(A)视为同一条路径。

    输入输出格式

    输入格式:

    第一行输入三个正整数(n),(m),(K),表示有(n)个点(m)条边,要求的路径需要经过(K)个点。

    接下来输入(m)行,每行三个正整数(A_i,B_i,C_i(1le A_i,B_ile n,1 le C_ile10000)),表示(A_i)(B_i)间有一条长度为(C_i)的边。

    数据保证输入的是连通的无向图。

    输出格式:

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

    说明

    对于所有数据(nle30000,mle60000)(2le Kle n)

    数据保证最短路径树上至少存在一条长度为K的路径。


    Solution

    第二自然段的题意我现在都没弄懂。

    用我的理解就是先保证最短路,然后保证连边的编号的字典序是最小的。

    这个可以先把最短路图跑出来,然后对每个点的出边排序,从(1)开始跑(DFS),边跑边连边

    然后就是淀粉质了。

    吐槽题意+强行拼题+写起来不爽(不是为了了解一下最短路树我才不写呢)

    复杂度(O(nlogn))


    Code:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #include <queue>
    const int N=3e4+10;
    struct Edge
    {
        int v,w;
        bool friend operator <(Edge n1,Edge n2){return n1.v<n2.v;}
    }t;
    std::vector <Edge> e[N],e0[N];
    int n,m,k;
    const int inf=0x3f3f3f3f;
    #define P std::pair <int,int>
    std::priority_queue <P,std::vector <P >,std::greater <P> > q;
    int dis[N],used[N];
    int head[N],to[N<<1],edge[N<<1],Next[N<<1],cnt;
    void add(int u,int v,int w)
    {
        to[++cnt]=v,Next[cnt]=head[u],edge[cnt]=w,head[u]=cnt;
    }
    void disj()
    {
        memset(dis,0x3f,sizeof(dis));
        q.push(std::make_pair(dis[1]=0,1));
        while(!q.empty())
        {
            int u=q.top().second;
            q.pop();
            if(used[u]) continue;
            used[u]=1;
            for(int i=0;i<e[u].size();i++)
            {
                int v=e[u][i].v,w=e[u][i].w;
                if(dis[v]>dis[u]+w)
                {
                    dis[v]=dis[u]+w;
                    q.push(std::make_pair(dis[v],v));
                }
            }
        }
        memset(used,0,sizeof(used));
    }
    void dfsbuild(int now)
    {
        used[now]=1;
        for(int i=0;i<e0[now].size();i++)
        {
            int v=e0[now][i].v,w=e0[now][i].w;
            if(!used[v])
            {
                add(now,v,w);
                add(v,now,w);
                dfsbuild(v);
            }
        }
    }
    void build()
    {
        for(int u=1;u<=n;u++)
        {
            for(int i=0;i<e[u].size();i++)
            {
                int v=e[u][i].v,w=e[u][i].w;
                if(dis[v]==dis[u]+w)
                    t={v,w},e0[u].push_back(t);
            }
            std::sort(e0[u].begin(),e0[u].end());
        }
        dfsbuild(1);
    }
    int ans,siz[N],rt,mi,mxlen[N],mx,del[N],td[N],tmxlen[N],scnt[N],tcnt[N];
    int max(int x,int y){return x>y?x:y;}
    void dfsroot(int now,int fa,int sz)
    {
        siz[now]=1;
        int mx0=0;
        for(int i=head[now];i;i=Next[i])
        {
            int v=to[i];
            if(v==fa||del[v]) continue;
            dfsroot(v,now,sz);
            mx0=max(mx0,siz[v]);
            siz[now]+=siz[v];
        }
        mx0=max(mx0,sz-siz[now]);
        if(mx0<mi) mi=mx0,rt=now;
    }
    void dfs(int now,int fa,int dis,int dep)
    {
        if(dep>k) return;
        if(mx<dis+mxlen[k-dep])
        {
            mx=dis+mxlen[k-dep];
            ans=scnt[k-dep];
        }
        else if(mx==dis+mxlen[k-dep])
            ans+=scnt[k-dep];
        for(int i=head[now];i;i=Next[i])
        {
            int v=to[i];
            if(v==fa||del[v]) continue;
            dfs(v,now,dis+edge[i],dep+1);
        }
        if(tmxlen[dep]<dis)
        {
            tmxlen[dep]=dis;
            tcnt[dep]=1;
        }
        else if(tmxlen[dep]==dis)
            tcnt[dep]++;
    }
    void dfz(int now,int sz)
    {
        mi=1<<30;
        dfsroot(now,0,sz);
        now=rt;
        del[now]=1;
        for(int i=head[now];i;i=Next[i])
        {
            int v=to[i];
            if(del[v]) continue;
            dfs(v,now,edge[i],1);
            for(int j=1;tmxlen[j]!=-inf;j++)
            {
                if(tmxlen[j]>mxlen[j])
                {
                    scnt[j]=tcnt[j];
                    mxlen[j]=tmxlen[j];
                }
                else if(tmxlen[j]==mxlen[j])
                    scnt[j]+=tcnt[j];
                tcnt[j]=0,tmxlen[j]=-inf;
            }
        }
        if(mx<mxlen[k]) ans=scnt[k],mx=mxlen[k];
        else if(mx==mxlen[k]) ans+=scnt[k];
        for(int i=1;mxlen[i]!=-inf;i++) mxlen[i]=-inf;
        for(int i=head[now];i;i=Next[i])
            if(!del[to[i]])
                dfz(to[i],siz[to[i]]);
    }
    int main()
    {
        //freopen("data.in","r",stdin);
        //freopen("wr.out","w",stdout);
        scanf("%d%d%d",&n,&m,&k);
        for(int u,v,w,i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            t={v,w};
            e[u].push_back(t);
            t={u,w};
            e[v].push_back(t);
        }
        disj();
        build();
        --k;
        for(int i=0;i<=k+1;i++)
            tmxlen[i]=mxlen[i]=-inf;
        dfz(1,n);
        printf("%d %d
    ",mx,ans);
        return 0;
    }
    
    

    2018.10.22

  • 相关阅读:
    word2vec原理(一) CBOW与Skip-Gram模型基础
    条件随机场CRF(三) 模型学习与维特比算法解码
    条件随机场CRF(二) 前向后向算法评估标记序列概率
    linux下如何强制卸载设备?
    docker build时如何使用代理?
    如何配置docker使用代理?
    linux下tar解压时报"gzip: stdin: unexpected end of file"如何处理?
    ubuntu下如何安装valgrind?
    linux下如何睡眠1ms?
    linux用户空间如何控制gpio?
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9829328.html
Copyright © 2011-2022 走看看