• 【BZOJ】1579: [Usaco2009 Feb]Revamping Trails 道路升级


    【算法】分层图最短路

    【题解】

    考虑k层一模一样的图,然后每个夹层都在每条边的位置新加从上一层跨越到下一层的边权为0的边,这样至多选择k条边置为0。

    然后考虑方便的写法。

    SPFA

    第一次SPFA计算常规最短路(顶层)。

    之后k次SPFA,松弛操作加上可以从上一层节点直接获取最短路(即相当于省一条边)

    这样可以保证一次SPFA最多只有一条边省略,因为你要么从上一层前一个点下来,其实是获取上一层前一个点的最短路。

    要么从前面一个点过来,其实是获取本层的最短路,本层最短路最多从上面下来一次。

    因为只与上一层有关,开滚动数组。

    SPFA记得SLF优化,不然较慢!

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxm=50010,maxn=10010;
    struct edge{int v,w,from;}e[maxm*3];
    int first[maxn],X,n,m,k,q[10010],tot=0;
    long long d[2][maxn];
    bool vis[maxn];
    void insert(int u,int v,int w)
    {tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;}
    void spfa()
    {
        memset(vis,0,n+1);
        memset(d[X],0x3f,8*(n+1));
        int head=0,tail=1;q[0]=1;vis[1]=1;d[X][1]=0;
        while(head!=tail)
         {
             int x=q[head++];if(head>10000)head=0;
             for(int i=first[x];i;i=e[i].from)
              if(d[X][e[i].v]>d[X][x]+e[i].w)
               {
                   int y=e[i].v;
                   d[X][y]=d[X][x]+e[i].w;
                   if(!vis[e[i].v])
                    {
                        if(d[X][y]<d[X][q[head]]){head--;if(head<0)head=10000;q[head]=y;}
                     else{q[tail++]=y;if(tail>10000)tail=0;}
                        vis[e[i].v]=1;
                    }
               }
             vis[x]=0;
         }
    //    for(int i=1;i<=n;i++)printf("%d ",d[X][i]);printf("
    ");
    }
    void spfas()
    {
    //    for(int i=1;i<=n;i++)d[X][i]=d[1-X][i];
        memset(d[X],0x3f,8*(n+1));
        int head=0,tail=1;q[0]=1;vis[1]=1;d[X][1]=0;
        while(head!=tail)
         {
             int x=q[head++];if(head>10000)head=0;//printf("q %d",x);
             for(int i=first[x];i;i=e[i].from)
              if(d[X][e[i].v]>min(d[X][x]+e[i].w,d[1-X][x]))
               {
                   int y=e[i].v;
                   d[X][y]=min(d[X][x]+e[i].w,d[1-X][x]);
                   if(!vis[e[i].v])
                    {
                        if(d[X][y]<d[X][q[head]]){head--;if(head<0)head=10000;q[head]=y;}
                     else{q[tail++]=y;if(tail>10000)tail=0;}
                        vis[e[i].v]=1;
                    }
               }
             vis[x]=0;
         }
    //    for(int i=1;i<=n;i++)printf("%d ",d[X][i]);printf("
    ");
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=m;i++)
         {
             int u,v,w;
             scanf("%d%d%d",&u,&v,&w);
             insert(u,v,w);
             insert(v,u,w);
         }
        X=0;
        spfa();
        for(int i=1;i<=k;i++)
         {
             X=1-X;
             spfas();
         }
        printf("%lld",d[X][n]);
        return 0;
    }
    View Code

    Dijkstra

    效率相似,但是写法简单很多,只要记录多一维层次,每次更新的时候附带上到下一层的更新,然后根据dij每次选择最短的更新的特点,第一次到达n就是答案了。

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    const int maxn=100010;
    struct edge{int v,w,from;}e[maxn];
    struct cyc{
        int x,k,d;
        bool operator < (const cyc &a)const{
            return d>a.d;
        }
    };
    priority_queue<cyc>q;
    int n,m,first[maxn],tot,d[maxn][30],kind;
    
    
    void insert(int u,int v,int w){
        tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;
        tot++;e[tot].v=u;e[tot].w=w;e[tot].from=first[v];first[v]=tot;
    }
    int dijkstra(){
        q.push((cyc){1,0,0});
        memset(d,0x3f,sizeof(d));
        d[1][0]=0;
        while(!q.empty()){
            cyc x=q.top();q.pop();
            if(x.d!=d[x.x][x.k])continue;
            if(x.x==n)return x.d;
            for(int i=first[x.x];i;i=e[i].from){
                if(d[e[i].v][x.k]>d[x.x][x.k]+e[i].w){d[e[i].v][x.k]=d[x.x][x.k]+e[i].w;q.push((cyc){e[i].v,x.k,d[e[i].v][x.k]});}
                if(x.k<kind&&d[e[i].v][x.k+1]>d[x.x][x.k]){d[e[i].v][x.k+1]=d[x.x][x.k];q.push((cyc){e[i].v,x.k+1,d[e[i].v][x.k+1]});}
            }
        }
        return 0;
    }
    int main(){
        scanf("%d%d%d",&n,&m,&kind);
        int u,v,w;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&u,&v,&w);
            insert(u,v,w);
        }
        printf("%d",dijkstra());
        return 0;
    }
    View Code
  • 相关阅读:
    lvs+keepalived+nginx
    linux配置静态ip
    nginx+keepalived
    nginx反向代理+负载均衡
    win10 安装虚拟机问题
    zlib-1.2.8用VS2010编译生成动态静态库
    mysql 创建库时指定编码
    mysql 升级遇到的问题 (本次由5.1.1X到5.6.28)
    android的SDK包下载
    node-webkit 使用笔记
  • 原文地址:https://www.cnblogs.com/onioncyc/p/6637133.html
Copyright © 2020-2023  润新知