【Usaco2014Open银组】双导航(gpsdual)
题目
【题目描述】
FJ 最近网购了一台小车。但是由于他的草率,在选择加装物品时偶然地点击了两次“Submit” ,结果最后他的小车装了两台GPS 导航系统!更糟的是,这两个系统对于FJ 要走的路线经常做出矛盾的判断。
FJ 居住地区的地图由N 个路口(2<=N <=10,000)和M 条有向边(1<=M<=50,000)组成。第i 条路连接路口Ai(1 <=Ai<=N)和Bi(1 <=Bi<=N)。对于同一对路口,可能有多条路连接它们;并且一条无向边会被表示成两条方向相反,连接路口相同的边。FJ 的房子位于第一路口,他的农场位于路口N。从他的房子出发,经过一系列有向边,是可以到达农场的。
两个GPS 系统基于如上面所描述的相同地图。然而,每条路它们存储的通过所需时间不相同。道路i 根据第一GPS 系统需要Pi 单位时间来通过,根据第二GPS 系统需要Qi 单位时间来通过(每个通过时间均是在1 到100,000 范围内的整数)。
FJ 想要从他的房子自驾车到农场。然而,当FJ 在一条某一个GPS 系统认为不属于最短路径内(从道路起始点X 到农场的最短路径)的道路(从路口X 到路口Y )上行驶时,这个GPS 系统会大声警告(如果FJ 选择的道路两个系统都不认可,那么两个系统都会警告FJ)。
请帮助FJ 找出,如果他恰当地选择他的路线,他能收到的警告最少是多少。
如果当FJ 沿一条道路走的时候两个GPS 都在警告,那么总警告数+2。
【输入】
第一行,整数N 和M。
接下来M 行,第i 行有四个整数Ai,Bi, Pi,Qi 描述第i 条道路。
【输出】
输出单独一行一个整数——FJ 选择从他家到达农场的最佳线路之后,路上收到的最小总警告数。
【样例输入】
5 7
3 4 7 1
1 3 2 20
1 4 17 18
4 5 25 3
1 2 10 1
3 5 4 14
2 4 6 5
【样例输出】
1
【样例解释】
输入详述:这里有5 个路口和7 条有向道路。第一条道路从路口3 到路口4 连接两个路口;第一GPS 认为这条路需要7 单位时间来通过,接着第二GPS 认为它只需1单位时间,诸如此类。
输出详述:如果FJ 按照路线1->2->4->5 走,那么第一GPS 会在1->2 这条路上发出警告(它认为1->3 这条路更好)。然而,对于路线剩下的2->4->5,两个GPS 都快乐地坐着FJ 的小车通过了,因为每个GPS 都以为这是2 到5 的最短路。
题解
这题主要讲了Farmer John把奶牛们打包送到肯德基后赚了一大笔钱,就网购小汽车。不料脑子瓦特了一下,订了两个GPS。店家黑心,没有告诉FJ这一消息,反而给了他两个版本不同的、声音响亮的GPS导航,这两个导航会在FJ不在走它们所认为的最短路时鸣叫,苦苦折磨着可怜的FJ。FJ就决定找一条去农场的最佳路径,使他被折磨的次数最少。
这题一眼扫过去,最短路算法!
没错,这题就是最短路,直觉没有坑害你。
于是一些人就立刻敲代码了,但是,怎么最短路呢?!
First,做这道题之前,你必须明白一件事——所谓的最短路是指到终点的最短路,当FJ从点 i 出发,走的边不是GPS认为的从点 i 出发去终点所要走的边时(即不在点 i 到终点的最短路上)就会发出警告。
所以要初始化从每一个点出发到终点要走那一条边(只会走一条)。
怎么弄呢?其实可以先跑一次SPFA,计算第一个GPS中每一个点到终点的距离(设第 i 个点的距离为\({dis1_{i}}\)),跑一次SPFA,计算第二个GPS中每一个点到终点的距离(设第 i 个点的距离为\({dis2_{i}}\))。根据SPFA算法的思路,可以推出,对于每一个导航,当点 i 和点 j 通过第 k 条边相连,点 j 到终点的距离被点 i 通过第 k 条边更新时,如果后来都没有任何点更新了点 i 和点 j 的最短路,那么\({dis_{i}+lenth_{k}=dis_{j}}\)(\(lenth_{k}\)表示第k条边的长度),由于对于每一个导航都是如此,我就用\(dis\)来代替\(dis1\)和\(dis2\)了。
如果点 i 离终点的最短距离被更新了,那么\(dis_{i}+lenth_{k}<dis_{j}\),如果点 j的被更新了,那么\(dis_{i}+lenth_{k}>dis_{j}\)。有人就要问了,如果i和j都被更新了怎么办?那样就必须再白一件事:如果点j到终点的最短路径中仍然是要经过点i的话,那么\(dis_{i}+lenth_{k}=dis_{j}\)(想一想,为什么);如果点j到终点的最短路径已经不用经过点i,那么\(dis_{i}+lenth_{k}<dis_{j}\)。
所以,再求出最短路径后,我们就可以枚举每一条边。设这条边的起点是u,终点是v,编号是i,当导航1在FJ经过这一条边时会发出警告,就一定会满足\(dis1_{i}+lenth_{k}>dis1_{j}\);当导航2在FJ经过这一条边时会发出警告,就一定会满足\(dis2_{i}+lenth_{k}>dis2_{j}\)
但是,这一切都搞定了,怎么求最少警告次数呢?
最短路!
我们可以视如果FJ经过一条边会被警告k次,那这一条边的权值就为k,这样弄完以后,再从起点出发跑一次SPFA就好了。
提示:由于本题要跑多次SPFA,建议建一个专门的函数来做SPFA。
代码
#include<cstdio>
#include<cstdlib>
using namespace std;
struct edge
{
int From,Lenth,To;
void swap()
{
int t=From;
From=To;
To=t;
}
}a[50010],b[50010],c[50010];
int n,m,dis[10010],date[51000],start[10010],end[10010];
bool exist[10010];
int cmp(const void *x,const void *y)
{
edge xx=*(edge*)x,yy=*(edge*)y;
if(xx.From!=yy.From) return xx.From-yy.From;
return xx.To-yy.To;
}
void spfa(int st)
{
int i,j,u,v,head=0,tail=1;
qsort(a+1,m,sizeof(edge),cmp);
for(i=1;i<=n;i++) dis[i]=2e9;
a[m+1].From=0;
for(i=1;i<=m+1;i++)
{
if(a[i].From!=a[i-1].From)
{
start[a[i].From]=i;
end[a[i-1].From]=i-1;
}
}
date[1]=st,dis[st]=0;
while(head<tail)
{
head++;
if(head==51000) head=1;
u=date[head];
exist[u]=0;
for(i=start[u];i<=end[u];i++)
{
v=a[i].To;
if(dis[u]+a[i].Lenth<dis[v])
{
dis[v]=dis[u]+a[i].Lenth;
if(!exist[v])
{
exist[v]=1;
tail++;
if(tail==51000) tail=1;
date[tail]=v;
}
}
}
}
}
int main()
{
freopen("gpsdual.in","r",stdin);
freopen("gpsdual.out","w",stdout);
int i,j,k,x,y,lena,lenb,t;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
scanf("%d%d%d%d",&x,&y,&lena,&lenb);
a[i]=(edge){y,lena,x};
b[i]=(edge){y,lenb,x};
c[i]=(edge){y,0,x};
}
qsort(c+1,m,sizeof(edge),cmp);
spfa(n);
for(i=1;i<=m;i++)//交换
{
if(dis[a[i].From]+a[i].Lenth>dis[a[i].To]) c[i].Lenth++;
a[i]=b[i];
}
spfa(n);
for(i=1;i<=m;i++)//交换
{
if(dis[a[i].From]+a[i].Lenth>dis[a[i].To]) c[i].Lenth++;
c[i].swap();
a[i]=c[i];
}
spfa(1);
printf("%d\n",dis[n]);
return 0;
}
【Usaco2014Open银组】双导航(gpsdual)的更多相关文章
- BZOJ USACO 银组 水题集锦
最近刷银组刷得好欢快,好像都是水题,在这里吧他们都记录一下吧(都是水题大家一定是道道都虐的把= =)几道比较神奇的题到时再列出来单独讲一下吧= =(其实我会说是BZOJ蹦了无聊再来写的么 = =) [ ...
- usaco 2010年3月银组题解
usaco银组解题报告 一.石子游戏如果把‘O’当作0,‘X’当做1,则N个洞的每一种状态都可以看做是一个N位二进制数.于是,这个问题就变成了求环绕的N位格雷码.幸运的是,这个结构很容易就能够用一个简 ...
- Bootstrap -- 下拉菜单、输入框组、导航菜单
Bootstrap -- 下拉菜单.输入框组.导航菜单 1. 下拉菜单 可以使用带有各种大小按钮的下拉菜单:.btn-lg..btn-sm 或 .btn-xs. 实现下拉菜单: <!DOCTYP ...
- Android典型界面设计(3)——访网易新闻实现双导航tab切换
一.问题描述 双导航tab切换(底部区块+区域内头部导航),实现方案底部区域使用FragmentTabHost+Fragment, 区域内头部导航使用ViewPager+Fragment,可在之前博客 ...
- Android典型界面设计(7) ——DrawerLayout+Fragement+ViewPager+PagerTabStrip实现双导航
一.问题描述 在Android典型界面设计(3)的我们实现了双导航效果,即外层底部导航和内部区域的头部导航,如网易新闻等很多应用采用了这种导航,但Google提供DrawerLayout可实现抽屉式导 ...
- Android典型界面设计-访网易新闻实现双导航tab切换
一.问题描述 双导航tab切换(底部区块+区域内头部导航),实现方案底部区域使用FragmentTabHost+Fragment, 区域内头部导航使用ViewPager+Fragment,可在之前博客 ...
- bootstrap学习笔记<十>(按钮组,导航)
1)按钮组.样式:class="btn-group" <div class="btn-group"> <button class=" ...
- bootstrap输入框组、导航和导航条
输入框组(input groups) 避免使用select 支持不好,使用输入框组 尺寸根据 input-group-lg input-group-sm来选择 <div class ...
- Android典型界面设计(8) ——ViewPager+PagerSlidingTabStrip实现双导航
一.问题描述 PagerSlidingTabStrip是android开源项目,指示器控件.官网地址:https://github.com/astuetz/PagerSlidingTabStrip 该 ...
随机推荐
- EasySwoole 在mac上装虚拟机centos共享mac目录报错处理
[2019-09-26 21:37:09][DEBUG][ERROR] : [listen /media/psf/Home/wwwroot/myobj/easyswoole/Temp/TaskWork ...
- 2016 CCPC 长春站现场赛总结(流水账= =)
总的来说在写这篇总结的时候心情还是愉悦的,因为第一次参加区域赛就越过铜直接拿了个银~开心之情无法用语言形容啊233= =... 从杭州坐火车到长春,去的时候24个小时,回来32个小时,在路上就花了2天 ...
- brute爆破
0X01明文传输的表单爆破用户名和密码 不存在任何加密 直接爆破即可 当不存在用户名时: 当存在用户名时,密码错误: 这里由于靶场关了 所以我们用dvwa演示 但是dvwa没有以上的差别 所以我们默认 ...
- [BZOJ2208]:[Jsoi2010]连通数(暴力 or bitset or 塔尖?)
题目传送门 题目描述 度量一个有向图连通情况的一个指标是连通数,指图中可达顶点对的个数. 在上图中,顶点1可以到达1.2.3.4.5. 顶点2可以到达2.3.4.5. 顶点3可以到达3.4.5. 顶点 ...
- [CSP-S模拟测试]:数学课(找规律+数学)
题目传送门(内部题145) 输入格式 从$math.in$读入数据. 第一行两个数,为$n,q$.接下来$q$行每行一个数$m$,询问大小为$m$的$A$一共有多少个. 输出格式 输出答案到$math ...
- kentico中page alias的使用
这里设置的path or pattern,是针对于根目录而言的
- ELK- elasticsearch 讲解,安装,插件head,bigdesk ,kopf,cerebro(kopf升级版)安装
ElasticSearch:简称es ,分布式全文搜索引擎,使用java语言开发,面向文档型数据库,一条数据就是一个文档,数据用json序列化后存储. 默认端口:9200 借助redis来理解 red ...
- GitHub:Youtube
ylbtech-GitHub:Youtube 1.返回顶部 2.返回顶部 3.返回顶部 4.返回顶部 5.返回顶部 1. https://github.com/youtube 2. ...
- GitHub:Baidu
ylbtech-GitHub:Baidu 1.返回顶部 · duedge-recipes DuEdge百度边缘网络计算样例代码 edgeedge-computingduedge JavaScri ...
- 编写javad代码实现使用Scanner从键盘读取一行输入,去掉其中重复字符, 打印出不同的那些字符
package com.loaderman.test; import java.util.HashSet; import java.util.Scanner; public class Test2 { ...