cogs 826. [Tyvj Feb11] GF打dota 次短路详细原创讲解! dijkstra
826. [Tyvj Feb11] GF打dota
★★☆ 输入文件:dota.in
输出文件:dota.out
简单对比
时间限制:1 s 内存限制:128 MB
众所周知,GF同学喜欢打dota,而且打得非常好。今天GF和Spartan同学进行了一场大战。
现在GF拿到一张地图,地图上一共有n个地点,GF的英雄处于1号点,Spartan的基地位于n号点,
GF要尽快地选择较短的路线让他的英雄去虐掉Spartan的基地。但是Spartan早就料到了这一点,
他有可能会开挂(BS~)使用一种特别的魔法,一旦GF所走的路线的总长度等于最短路的总长度时,
GF的英雄就要和这种魔法纠缠不休。这时GF就不得不选择非最短的路线。现在请你替GF进行规划。
- 对于描述的解释与提醒:
- 1.无向路径,花费时间当然为非负值。
2.对于本题中非最短路线的定义:不管采取任何迂回、改道方式,
只要GF所走的路线总长度不等于1到n最短路的总长度时,就算做一条非最短的路线。
- 3.保证1~n有路可走。
输入:
第一行为n,m(表示一共有m条路径)
接下来m行,每行3个整数a,b,c,表示编号为a,b的点之间连着一条花费时间为c的无向路径。
接下来一行有一个整数p,p=0表示Spartan没有开挂使用这种魔法,p=1则表示使用了。
输出:
- 所花费的最短时间t,数据保证一定可以到达n。
样例输入1:
5 5
1 2 1
1 3 2
3 5 2
2 4 3
4 5 1
0
样例输入2:
5 5
1 2 1
1 3 2
3 5 2
2 4 3
4 5 1
1
- 样例输出1:
- 4
- 样例输出2:
- 5
对于50%的数据,1<=n,m<=5000
对于70%的数据,1<=n<=10000, 1<=m<=50000,p=0,
对于100%的数据,1<=n<=10000, 1<=m<=50000,p=1
无向图,花费时间c>=0
各个测试点1s
- 来源:lydliyudong Tyvj February二月月赛第二场 第2道
敬爱的读者:在这里抱歉地声明 接下来的一大段呕心沥血的讲解皆为不完全正确的
我一度认为 用一个dis2数组来表示从根节点到每一个点的次短路的值
但是经过认真思考 和跌坑儿后 我发现 不能这样子去做
求出对于一个点的次短路 并不能向另外的一个点去扩展
所以下面的内容仅做思维拓展(只有70分,我下面这个冒险的自创算法有不正确的情况存在!)
这一道题真的是太难了额,发现自己最近总是冲动想要自己去研究一些没学过的东西
那么怎样子用dijkstra来解决这一道坑人的题呢?
首先我们先来回忆一下dijkstra最短路是怎样求的
就是利用一个优先队列 往里面放一个个pair <dis[x],x> 去一个个松弛
那么求次短路怎么办呢?
突然间 我想到了一个异常暴力的做法
就是说 最短路肯定是整张图中最优最优的路径了 随便改变一下路径上的那一条边都不是最短路了
那么我们可以枚举一下删掉哪一条边 每一次跑一遍在删掉当前所枚举的边后的新图上跑dijkstra
很显然这个想法是非常正确的 也是没有什么意义的 因为这肯定效率非常的低下啊
所以我们要来想一种办法 使得在跑最短路的同时求出次短路?!?<<这真是一个神奇又看起来不太可能的想法
原来不是有一个数组是dis数组 来记录每一个点到根节点最短路的长度
那么我们再来设一个dis2数组 当然非常显然针对这一道题是没有什么很大的必要的
但是这样子可能会对我们以后解决一些比较共性的问题会有很大的帮助的♪(^∇^*)
经过10分钟的沉思 我终于想出了一种解决办法
您这么想:
我们再进行松弛操作的时候是从小到大的
有以下这么几种情况
1.现在枚举的dis[y]+v[x][i]<dis2[x]
也就是说 找到了更短的次短路 就swap一下
2.dis2[x]<dis1[x]
也就是说次短路比最短路还要短
那次短路和最短路 调一个个儿就行了
那么怎么证明上面的方法是正确的呢?
首先你第一个枚举的肯定是最小的对吧
你会在第一次循环中先把dis2更新
现在的dis2比dis1小 就swap一下 那么当前的最短路就是当前枚举的 次短路还是正无穷
其实这样子讲还是太抽象了
首先看第一个情况 更新次短路 这肯定是没有什么问题了 有更短的就更新一下 很正确啊
第二个情况呢?
如果dis2<dis1 就swap 对于最短路肯定是没有问题的 这样子dis1就成了枚举到当前时 的最短路
其实dis2的正确性也是可以保证的 因为dis1是原来先前所有情况中最短的 现在往后顺移 就成了第二短的 没有任何问题!
所以我们就可以付诸实施这个本人自己想出来的绝妙办法 啦
可惜只有70分 WA了30
#include<bits/stdc++.h>
#define maxn 10005
#define maxm 50005
#define pa pair<int,int>
using namespace std;
int n,m;
vector<int> v[maxn],w[maxn];
int dis1[maxn],dis2[maxn];
int vis[maxn];
priority_queue<pa,vector<pa>,greater<pa> > q;
void Dijkstra()
{
memset(dis1,0x3f,sizeof(dis1));
memset(dis2,0x3f,sizeof(dis2));
dis1[]=;
dis2[]=;
q.push(make_pair(,));
while(!q.empty())
{
int x=q.top().second;
q.pop();
if(vis[x])
continue;
vis[x]=;
for(int i=;i<v[x].size();i++)
{
int y=v[x][i];
if(dis2[y]>dis1[x]+w[x][i])
dis2[y]=dis1[x]+w[x][i];
if(dis2[y]<dis1[y])
swap(dis2[y],dis1[y]);
q.push(make_pair(dis1[y],y));
}
}
}
int main()
{
freopen("dota.in","r",stdin);
freopen("dota.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
v[x].push_back(y);
v[y].push_back(x);
w[x].push_back(z);
w[y].push_back(z);
}
Dijkstra();
int p;
scanf("%d",&p);
if(p)
printf("%d",dis2[n]);
else
printf("%d",dis1[n]);
return ;
}
这是70分的代码
经过3天的苦苦思考 我仿佛想出了一个反例
就是说如果按照我上面的做法 可能会出现 一种情况
就是 求出来的次短路和最短路的数值是相同的
比如有两条路径走出来都是4
那么最短路和次短路答案就都成了4
非常的苦闷
现在我们还是来正八经儿地讲一下比较普遍认可的做法吧(我太蒟了 自创了一个算法错了)
好 ,这一道题的正解是
跑两边dijkstra 是不是非常的荒唐?
就是以1为根正着来一遍 以n为根反着来一遍
正着的是dis1数组 反着的是dis2数组 我们可以发现
我们可以枚举每一条边
这一条边的两个端点是u v
u比较靠近1 v比较靠近n
那么我们只要找到最小的不等于最短路的次短路即可
就是dis1[u]+边权+dis2[v]中取一个最小的即可
然而 还是70分 严重抗议!这一道题有问题吧~
#include<bits/stdc++.h>
#define maxn 10005
#define pa pair<int,int>
using namespace std;
int vis1[maxn],vis2[maxn],vis3[maxn],dis1[maxn],dis2[maxn];
priority_queue<pa,vector<pa>,greater<pa> > q;
vector<int> v[maxn],w[maxn];
int n,m;
void Dijkstra1()
{
memset(dis1,0x3f,sizeof(dis1));
dis1[]=;
q.push(make_pair(,));
while(!q.empty())
{
int x=q.top().second;
q.pop();
if(vis1[x])
continue;
vis1[x]=;
for(int i=;i<v[x].size();i++)
{
int y=v[x][i];
if(dis1[y]>dis1[x]+w[x][i])
{
dis1[y]=dis1[x]+w[x][i];
q.push(make_pair(dis1[y],y));
}
}
}
}
void Dijkstra2()
{
memset(dis2,0x3f,sizeof(dis2));
dis2[n]=;
q.push(make_pair(,));
while(!q.empty())
{
int x=q.top().second;
q.pop();
if(vis2[x])
continue;
vis2[x]=;
for(int i=;i<v[x].size();i++)
{
int y=v[x][i];
if(dis2[y]>dis2[x]+w[x][i])
{
dis2[y]=dis2[x]+w[x][i];
q.push(make_pair(dis2[y],y));
}
}
}
}
int Min=0x3f3f3f3f;
void Dfs(int x)
{
if(vis3[x])
return;
vis3[x]=;
for(int i=;i<v[x].size();i++)
{
int y=v[x][i];
int Dis=dis1[x]+w[x][i]+dis2[y];
if(Dis!=dis1[n]&&Dis<Min)
Min=Dis;
Dfs(y);
}
}
int main()
{
freopen("dota.in","r",stdin);
freopen("dota.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
v[x].push_back(y);
v[y].push_back(x);
w[x].push_back(z);
w[y].push_back(z);
}
Dijkstra1();
int p;
scanf("%d",&p);
if(p==)
{
printf("%d",dis1[n]);
return ;
}
Dijkstra2();
Dfs();
printf("%d",Min);
return ;
}
已然是70分 谁来救救我啊
下面上一个神奇的满分做法 A*
#include<bits/stdc++.h>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>//系统快排必加
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
const int maxn=;
int n,m,dis[maxn];vector<int>son[maxn],v[maxn];
bool bein[maxn];queue<int>q;
void Set(int prt,int to,int d){
son[prt].push_back(to),v[prt].push_back(d);
}
void spfa(int s){
memset(dis,0x3f,sizeof(dis));
dis[s]=,q.push(s),bein[s]=true;
while(!q.empty()){
int rt=q.front();q.pop(),bein[rt]=false;
for(int i=;i<son[rt].size();i++){
int to=son[rt][i];
if(dis[to]>dis[rt]+v[rt][i]){
dis[to]=dis[rt]+v[rt][i];
if(!bein[to])bein[to]=true,q.push(to);
}
}
}
}
struct node{
int x,d;
bool operator<(const node &a)const{
return d+dis[x]>a.d+dis[a.x];
}
};priority_queue<node>Q;
int Astar(int s,int t){
Q.push((node){s,});
while(!Q.empty()){
node prt=Q.top();Q.pop();int rt=prt.x;
if(rt==t&&prt.d>dis[s])return prt.d;
for(int i=;i<son[rt].size();i++)
Q.push((node){son[rt][i],prt.d+v[rt][i]});
}
}
int main()
{
freopen("dota.in","r",stdin);
freopen("dota.out","w",stdout);
int x,y,z,p;
cin>>n>>m;
int i;
while(m--)
cin>>x>>y>>z,Set(x,y,z),Set(y,x,z);
spfa(n);
cin>>p;
if(p==)
cout<<dis[];
else
cout<<Astar(,n);
return ;
}
cogs 826. [Tyvj Feb11] GF打dota 次短路详细原创讲解! dijkstra的更多相关文章
- cogs 826. [Tyvj Feb11] GF打dota
826. [Tyvj Feb11] GF打dota ★★☆ 输入文件:dota.in 输出文件:dota.out 简单对比时间限制:1 s 内存限制:128 MB 众所周知,GF同学喜 ...
- COGS——T 826. [Tyvj Feb11] GF打dota
http://www.cogs.pro/cogs/problem/problem.php?pid=826 ★★☆ 输入文件:dota.in 输出文件:dota.out 简单对比时间限制:1 ...
- COGS 1191. [Tyvj Feb11] 猫咪的进化
★ 输入文件:neko.in 输出文件:neko.out 简单对比时间限制:1 s 内存限制:128 MB [背景] 对于一只猫咪来说,它是有九条命的.但是并不是所有的猫咪都是这样,只 ...
- COGS 827. [Tyvj Feb11] 网站计划
输入文件:web.in 输出文件:web.out 简单对比时间限制:1 s 内存限制:128 MB 描述 Description Tyvj的Admin--zhq同学将在寒假开始实行 ...
- [TYVJ] P1423 GF和猫咪的玩具
GF和猫咪的玩具 描述 Description GF同学和猫咪得到了一个特别的玩具,这个玩具由n个金属环(编号为1---n),和m条绳索组成,每条绳索连接两个不同的金属环,并且长度相同.GF左手拿起金 ...
- COGS 1215. [Tyvj Aug11] 冗余电网
★ 输入文件:ugrid.in 输出文件:ugrid.out 简单对比时间限制:1 s 内存限制:128 MB TYVJ八月月赛提高组第2题 测试点数目:5 测试点分值:20 --内存 ...
- cogs——1215. [Tyvj Aug11] 冗余电网
1215. [Tyvj Aug11] 冗余电网 ★ 输入文件:ugrid.in 输出文件:ugrid.out 简单对比 时间限制:1 s 内存限制:128 MB TYVJ八月月赛提高组 ...
- cogs 1829. [Tyvj 1728]普通平衡树 权值线段树
1829. [Tyvj 1728]普通平衡树 ★★★ 输入文件:phs.in 输出文件:phs.out 简单对比时间限制:1 s 内存限制:1000 MB [题目描述] 您需要写一种数 ...
- tyvj 1423 GF和猫咪的玩具
传送门 解题思路 题目比较水,floyd求出最短路取个最小值即可.结果joyoi时限写错了..好像只有0ms才能过??突然发现加了快读就T不加就A,数据在10000以下的还是scanf快啊. 代码 # ...
随机推荐
- dotnet 设计规范 · 抽象类
X 不要定义 public 或 protected internal 访问的构造函数.默认 C# 语言不提供抽象类的公开构造函数方法. 如果一个构造函数定义为公开,只有在开发者需要创建这个类的实例的时 ...
- hiveservice简介
由于实验的须要,这两天就搭了个Hive,简单记录一下: 平台:OS:Ubuntu Kylin 14.04 JAVA:Java 1.8.0_25 HADOOP:Hadoop 2.4.0 HIVE:Hiv ...
- python 使用PyInstaller遇到的坑
给个链接 https://github.com/yinghualuowu/Python_VLPR/releases 参数问题 在网上随处可以见到PyInstaller的参数教程. -F : 打包成单个 ...
- H3C 环路避免机制三:毒性逆转
- HDU6581 Vacation (HDU2019多校第一场1004)
HDU6581 Vacation (HDU2019多校第一场1004) 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6581 题意: 给你n+1辆汽车, ...
- 【Docker】初识与应用场景认知
什么是Docker? Docker是一个容器化平台,它以容器的形式将您的应用程序及其所有依赖项打包在一起,以确保您的应用程序在任何环境中无缝运行. 什么是Docker容器? Docker容器包括应用程 ...
- C\C++串口通信编程的一点技术记录
新工作接的第一个活,要写一个配合设备调试的上位机程序. 除了MFC界面的部分,就是要处理几条命令. 串口通信部分代码借鉴的是这一篇文章:http://blog.sina.com.cn/s/blog_a ...
- 阿里巴巴java开发手册学习记录,php版
一.编程规约 (一)命名风格 1.目录使用小写+下划线 home,view,model,admin_view 2.类 UpperCamelCase PhpMailer方法 lowerCamelCase ...
- #mysql查询特定数据库中的所有表名
#mysql查询特定数据库中的所有表名select table_namefrom information_schema.tableswhere table_schema='smbms' and tab ...
- TCP/IP||UDP广播和多播
1.概述 广播和多播应用于UDP,TCP是一个面向连接协议,意味着分别运行与两个主机内的两进程间存在一个连接,在考虑多个主机内的共享通信网络,每个以太网帧包含源主机和目的主机以太网地址(48bit), ...