题意描述

[BOI 2002]双调路径

题意描述的确实不是很清楚(出题人惜字如金)。

给定一张有 \(n\) 个点,\(m\) 条边的无向图,每条边有两个权值,分别表示经过这个点的代价和时间。

同时给出起点 \(s\) 和终点 \(t\),显然 \(s\to t\) 的路径有很多条。

其中说路径 A 比路径 B 更优,当且仅当 A 的代价和时间都小于 B。

当没有路线比这条路线更优时,称这条路线为最优路线。题目要求求 \(s\to t\) 的最优路线的条数。

注意:这里的最优路线可以有很多条,如果 \(time_A>time_B\) 但是 \(price_A<price_B\) 则两者谁也不优于谁。

同时,当两条路线代价和时间都相等时,成这两条路线为一条。(这里很良心了)

算法分析

基本思路

这里是双权值的最短路问题,比较直接的方法是以代价为关键字来枚举路径,每次选取时间最小的路径即可。

但是可以发现这种暴力算法将耗费大量时间用于判断代价是否相同,时间复杂度将非常恐怖,所以当场枪毙。

当时这种思想也给了我们启发,一番整理后有了一个可行的思想:

令 \(dis(i,j)\) 表示从 \(s\) 到 \(i\) 的代价为 \(j\) 的最短时间,那么显然有递推式:

\[dis(i,j)=min_{k\to i\in E}\{dis(k,j-price_{k,i})+time_{k,i}\}
\]

统计答案时,我们一次遍历 \(dis(t,i)(0\leq i\leq 10000)\)。(其中 10000 为数据范围内的最大代价)

同时维护一个 \(mn\) 表示当前时间的最小值,当 \(dis(t,i)<mn\) 时,更新 \(mn\) 并且令 ans++

这就表示:当一条路径的代价比你大(从小到大枚举)但时间比你少时,这是最优路径之一。

然后再时限放宽之后应该就是可以过了。(2020.4.22)

时间优化

但是在之前,这还是一道紫题的时候...,它的实现是 0.1s,这么“滥用”最短路肯定是过不去的。

那怎么办呢?

可以发现,根据 OI 定理:当一个人比你小还比你强时,你就可以退役了

换句话说:如果在你之前存在一条路径,代价和时间都比你小,那么你不可能是最优路径。

不仅如此,你所拓展的路径也不可能是最优路径。(自证不难)

所以我们可以利用树状数组进行优化,记录下区间最小值即可。(记得是二位树状数组)

代码实现

实现比较简单,说实话思路也没有难到哪里去。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
#include<algorithm>
#define N 1100
#define M 3100
#define C 10010
using namespace std; int n,m,s,t,head[N],cnt=0,dis[N][C],tree[N][C];
bool vis[N][C];
struct Edge{
int nxt,to,w1,w2;
}ed[M<<1]; int read(){
int x=0,f=1;char c=getchar();
while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0' && c<='9') x=x*10+c-48,c=getchar();
return x*f;
} void add(int u,int v,int c,int t){
ed[++cnt].nxt=head[u];
ed[cnt].to=v,ed[cnt].w1=c,ed[cnt].w2=t;
head[u]=cnt;
return;
} int lowbit(int x){return x&(-x);} void change(int x,int y,int z){
y++;
while(y<10100){
tree[x][y]=min(tree[x][y],z);
y+=lowbit(y);
}
return;
} int ask(int x,int y){
y++;
int mn=0x7fffffff;
while(y>=1){
mn=min(mn,tree[x][y]);
y-=lowbit(y);
}
return mn;
} void spfa(){
queue<pair<int,int> >q;
memset(dis,0x3f,sizeof(dis));
memset(tree,0x3f,sizeof(tree));
memset(vis,false,sizeof(vis));
dis[s][0]=0;
vis[s][0]=true;
q.push(make_pair(s,0));
change(s,0,0);
while(!q.empty()){
int w=q.front().second,u=q.front().first;
q.pop();
vis[u][w]=false;
for(int i=head[u];i;i=ed[i].nxt){
int v=ed[i].to;
int w1=ed[i].w1,w2=ed[i].w2;
int ww=w+w1;
if(ask(v,ww)>dis[u][w]+w2){
dis[v][ww]=dis[u][w]+w2;
change(v,ww,dis[v][ww]);
if(!vis[v][ww])
q.push(make_pair(v,ww)),vis[v][ww]=true;
}
}
}
return;
} int main(){
n=read(),m=read(),s=read(),t=read();
int u,v,w1,w2;
for(int i=1;i<=m;i++){
u=read(),v=read(),w1=read(),w2=read();
add(u,v,w1,w2),add(v,u,w1,w2);
}
spfa();
int mmin = 0x3f3f3f3f, ans = 0;
for (int i = 0; i <= 10000; i++) {
if (dis[t][i] < mmin)
mmin = dis[t][i], ans++;
}
printf("%d\n",ans);
return 0;
}

完结撒花

P5530 [BOI 2002]双调路径的更多相关文章

  1. 题解 P5530 [BalticOI 2002]双调路径

    P5530 [BalticOI 2002]双调路径 输入样例: 4 5 1 4 2 1 2 1 3 4 3 1 2 3 1 2 3 1 1 4 2 4 2 4 样例如下图 样例说明: 从1到4有4条路 ...

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

    Description 来越多,因此选择最佳路径是很现实的问题.城市的道路是双向的,每条道路有固定的旅行时间以及需要支付的费用.路径由连续的道路组成.总时间是各条道路旅行时间的和,总费用是各条道路所支 ...

  3. bzoj1375 双调路径

    Description 来越多,因此选择最佳路径是很现实的问题.城市的道路是双向的,每条道路有固定的旅行时间以及需要支付的费用.路径由连续的道路组成.总时间是各条道路旅行时间的和,总费用是各条道路所支 ...

  4. [bzoj1375] [Baltic2002] Bicriterial routing 双调路径

    Description 如今的道路收费发展很快.道路的密度越来越大,因此选择最佳路径是很现实的问题.城市的道路是双向的,每条道路有固定的旅行时间以及需要支付的费用. 路径是连续经过的道路组成的.总时间 ...

  5. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  6. 8.2/baltic神(水)题

    summary:10 bzoj1334: Description N个政党要组成一个联合内阁,每个党都有自己的席位数. 现在希望你找出一种方案,你选中的党的席位数要大于总数的一半,并且联合内阁的席位数 ...

  7. POJ 2677 Tour

    题意:双调欧几里得旅行商问题.算法导论15-1题,从最左边的点严格从左走到右再从右走到左回到起点,所有点都要走且只走一次,求最短路径. 解法:定义dp[i][j]表示从i走到j的双调路径,分为两种情况 ...

  8. loj题目总览

    --DavidJing提供技术支持 现将今年7月份之前必须刷完的题目列举 完成度[23/34] [178/250] 第 1 章 贪心算法 √ [11/11] #10000 「一本通 1.1 例 1」活 ...

  9. 【正睿oi省选十连测】第一场

    四小时写了两个暴力??自闭 [原来这就是神仙们的分量Orz rank 56/75 可以说是无比垃圾了 下周目标:进步十名?[大雾 T1 题意:有n个点的图 点有点权Ai 也有点权Bi = A_1 + ...

随机推荐

  1. Linux系统编程 —时序竞态

    时序竞态 什么是时序竞态?将同一个程序执行两次,正常情况下,前后两次执行得到的结果应该是一样的.但由于系统资源竞争的原因,前后两次执行的结果有可能得到不一样的结果,这个现象就是时序竞态. pause函 ...

  2. C# 主界面的扁平化

    如果需要查看更多文章,请微信搜索公众号 csharp编程大全,需要进C#交流群群请加微信z438679770,备注进群, 我邀请你进群! ! ! --------------------------- ...

  3. install Wine + WeChat in Fedora 31

    install Wine + WeChat in Fedora 31 dnf -y install dnf-plugins-core dnf config-manager --add-repo htt ...

  4. 数据结构与算法:AVL树

    AVL树 在计算机科学中,AVL树是最先发明的自平衡二叉查找树.在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树.增加和删除可能需要通过一次或多次树旋转来重新平衡这个树.AV ...

  5. Python 疑难问题:[] 与 list() 哪个快?为什么快?快多少呢?

    本文出自"Python为什么"系列,请查看全部文章 在日常使用 Python 时,我们经常需要创建一个列表,相信大家都很熟练了吧? # 方法一:使用成对的方括号语法 list_a ...

  6. jvm堆内存和GC简介

    最近经常遇到jvm内存问题,觉得还是有必要整理下jvm内存的相关逻辑,这里只描述jvm堆内存,对外内存暂不阐述. jvm内存简图 jvm内存分为堆内存和非堆内存,堆内存分为年轻代.老年代,非堆内存里只 ...

  7. redis 各种数据结构的encoding实现

    redis 各种数据结构的encoding实现 Redis type命令实际返回的就是当前键的数据结构类型,它们分别是:string(字符串).hash(哈希).list(列表).set(集合).zs ...

  8. centos8安装sersync为rsync实现实时同步

    一,查看本地centos的版本: [root@localhost lib]# cat /etc/redhat-release CentOS Linux release 8.1.1911 (Core) ...

  9. linux(fedora30):安装/配置maven(maven3.6.1)

    一,maven的用途 1,用途 Maven 是一个项目管理工具,主要用于项目构建,依赖管理,项目信息管理 maven可以用来: 帮用户下载jar包, 有依赖包时自动下载所需的依赖包 打包war包或ja ...

  10. ImageMagick实现图片的旋转/翻转/裁剪(ImageMagick6.9.10)

    一,imagemagick的安装 请参见: https://www.cnblogs.com/architectforest/p/12807514.html 说明:刘宏缔的架构森林是一个专注架构的博客, ...