双调路径

Posted fangbozhen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了双调路径相关的知识,希望对你有一定的参考价值。

https://loj.ac/problem/10083

题目描述

  给出一张图,每条边有两个边权,定义其最小路径为不存在一条路径两种边权都小于它的两种边权,求这张图的最小路径的条数。

思路

  首先这道题有两类边权,我们考虑把一类边权压入dis数组中,即我们用dis[i][j]表示到达i点,花费费用为j时所需要的最少时间。那么假设我们用w1表示i到j的费用,w2表示i到j的时间,那么dis[i][j]=dis[i][j-w1]+w2。这样我们可以直接进行最短路计算,这样已经足以通过这道题。

  不过我们考虑优化,如果存在一个f[j][k]<f[i][j]并且k<j,那么这就肯定不是最优解,不用再更新,而对k的维护,我们可以用树状数组维护f[i][0..j]中的最小值,再进行判断即可。结果我们只要遍历f[n][i],在费用单增情况下时间小即可。

代码

#include <bits/stdc++.h>
using namespace std;
struct aa
{
    int pos,val;
    aa(int pos=0,int val=0):pos(pos),val(val) {}
};
int nxt[660],to[660],w1[660],w2[660],head[330],tot;
int f[330][10005],dis[330][10005],N;
bool exist[330][10005];
void add_edge(int x,int y,int v,int tim)
{
    nxt[++tot]=head[x];
    head[x]=tot;
    to[tot]=y;
    w1[tot]=v;
    w2[tot]=tim;
}
int lowbit(int x)
{
    return x&(-x);
}
void add(int x,int y,int v)
{
    y++;
    for(;y<=N;y+=lowbit(y))f[x][y]=min(f[x][y],v);
}
int query(int x,int y)
{
    y++;
    int ans=0x3f3f3f3f;
    for(;y;y-=lowbit(y))ans=min(ans,f[x][y]);
    return ans;
}
void spfa(int s)
{
    memset(dis,0x3f,sizeof(dis));
    memset(f,0x3f,sizeof(f));
    queue<aa>q;
    q.push(aa(s,0));exist[s][0]=1;
    dis[s][0]=0;
    add(s,0,0);
    while(!q.empty())
    {
        aa u=q.front();q.pop();
        exist[u.pos][u.val]=0;
        for(int i=head[u.pos];~i;i=nxt[i])
        {
            int v=to[i],m=u.val+w1[i];
            if(query(v,m)>dis[u.pos][u.val]+w2[i])
            {    
                dis[v][m]=dis[u.pos][u.val]+w2[i];
                add(v,m,dis[v][m]);
                if(!exist[v][m])
                {
                    exist[v][m]=1;
                    q.push(aa(v,m));
                }
            }
        }
    }
}
int main() 
{
    int n,m,s,e;
    memset(head,-1,sizeof(head));
    scanf("%d%d%d%d",&n,&m,&s,&e);
    for(int i=1;i<=m;i++)
    {
        int a,b,c,d;
        scanf("%d%d%d%d",&a,&b,&c,&d);
        add_edge(a,b,c,d);add_edge(b,a,c,d);
    }
    N=n*100;
    spfa(s);
    int tim=0x3f3f3f3f,ans=0;
    for(int i=0;i<=N;i++)
        if(dis[e][i]<tim)ans++,tim=dis[e][i];
    printf("%d",ans);
    return 0;
}

 

以上是关于双调路径的主要内容,如果未能解决你的问题,请参考以下文章

Bicriterial routing 双调路径 HYSBZ - 1375(分层最短路)

双调路径

双调旅行商问题 (Bitonic TSP)

算法导论-15-1-双调欧几里得旅行商问题

OpenCL 双调排序 GPU 版

OpenCL 双调排序 CPU 版