zoukankan      html  css  js  c++  java
  • bzoj3694最短路

    bzoj3694最短路

    Description

    给出一个n个点m条边的无向图,n个点的编号从1~n,定义源点为1。定义最短路树如下:从源点1经过边集T到任意一点i有且仅有一条路径,且这条路径是整个图1到i的最短路径,边集T构成最短路树。 给出最短路树,求对于除了源点1外的每个点i,求最短路,要求不经过给出的最短路树上的1到i的路径的最后一条边。
     
    Input

    第一行包含两个数n和m,表示图中有n个点和m条边。
    接下来m行,每行有四个数ai,bi,li,ti,表示图中第i条边连接ai和bi权值为li,ti为1表示这条边是最短路树上的边,ti为0表示不是最短路树上的边。
    Output

    输出n-1个数,第i个数表示从1到i+1的要求的最短路。无法到达输出-1。
    Sample Input

    5 9
    3 1 3 1
    1 4 2 1
    2 1 6 0
    2 3 4 0
    5 2 3 0
    3 2 2 1
    5 3 1 1
    3 5 2 0
    4 5 4 0
    Sample Output

    6 7 8 5
    HINT

     对于100%的数据,n≤4000,m≤100000,1≤li≤100000


    solution

    我的方法很诡异

    首先删一条边相当于把一棵子树孤立出来。

    那么答案应要通过其他边绕到子树外面的点,再回到根。

    我们记d[i][j]表示以i为根的子树到其他点的最短路。

    可以用类似树形dp的方法把儿子的信息合并上来。

    O(n^2+m)

    其他方法

    考虑一条非树边,假设它连接了u,v

    那么他可以贡献的段为u~lca,u~lca

    树剖维护

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define maxn 4005
    #define inf 1e9
    using namespace std;
    int n,m,t1,t2,t3,t4,head[maxn],tot=1;
    int d[maxn][maxn],ans[maxn];
    int dfst[maxn],dfsn[maxn],sc,len[maxn],flag[maxn];
    struct node{
        int v,nex,w,op;
    }e[200005];
    void lj(int t1,int t2,int t3,int t4){
        e[++tot].v=t2;e[tot].w=t3;e[tot].op=t4;e[tot].nex=head[t1];head[t1]=tot;
    }
    void DFS(int k,int fa){
        dfst[k]=++sc;
        for(int i=head[k];i;i=e[i].nex){
            if(!e[i].op||e[i].v==fa)continue;
            len[e[i].v]=len[k]+e[i].w;
            DFS(e[i].v,k);
        }
        dfsn[k]=sc;
    }
    void dfs(int k,int fa,int b){
        for(int i=head[k];i;i=e[i].nex){
            if(!e[i].op||e[i].v==fa)continue;
            dfs(e[i].v,k,i);
        }
        for(int i=1;i<=n;i++)d[k][i]=inf;
        for(int i=head[k];i;i=e[i].nex){
            if(!e[i].op||e[i].v==fa)continue;
            for(int x=1;x<=n;x++)d[k][x]=min(d[k][x],d[e[i].v][x]+e[i].w);
            flag[e[i].v]=1;
        }//合并子树 
        for(int i=head[k];i;i=e[i].nex){
            if(i==(b^1))continue;
            d[k][e[i].v]=min(d[k][e[i].v],e[i].w);
        }// itself
        int l=dfst[k],r=dfsn[k];
        //cout<<"k: "<<k<<endl;
        ans[k]=inf;
        for(int x=1;x<=n;x++){
            //cout<<d[k][x]<<' ';
            if(dfst[x]<l||dfst[x]>r){
                ans[k]=min(ans[k],d[k][x]+len[x]);
            }
        }//cout<<endl;
        for(int i=head[k];i;i=e[i].nex){
            flag[e[i].v]=0;
        }
    }
    int main()
    {
        freopen("shortest.in","r",stdin);
        freopen("shortest.out","w",stdout);
        cin>>n>>m;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d%d",&t1,&t2,&t3,&t4);
            lj(t1,t2,t3,t4);lj(t2,t1,t3,t4);
        }
        DFS(1,0);
        //for(int k=1;k<=n;k++)cout<<k<<' '<<len[k]<<' '<<dfst[k]<<endl;
        dfs(1,0,0);
        if(ans[2]!=inf)printf("%d",ans[2]);
        else printf("-1");
        for(int i=3;i<=n;i++){
            if(ans[i]==inf)printf(" -1");
            else printf(" %d",ans[i]);
        }
        puts("");
        return 0;
    }
  • 相关阅读:
    演示Eclipse插件实现代码提示和补全
    重拾《 两周自制脚本语言 》- Eclipse插件实现语法高亮
    Kindle Windows版本 中文字体修改工具
    MD5加密算法原理及实现
    Spring boot 发送邮件示例
    ubuntu下svn的命令使用
    数据库的分区、分表、分库、分片的简介
    Vue 入门之目录结构介绍
    MQTT简单介绍与实现
    SVN使用规范
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358777.html
Copyright © 2011-2022 走看看