PAT A1003 Emergency

PAT A1003 Emergency

题目简述:

原题为英文题目,所以在这里简述一下题意:

给定n个点和m条无向路以及起点、终点

下面一行n个数,第i个数表示第i个点上的救援组数目(点权

再往下m行每行三个整数,表示每一条路连接的两个端点以及花费(边权

要求求出从起点到终点的最短路径数目以及最短路径上的最大救援组数目和


解题思路:

这道题和一般的最短路稍有不同:本题除了寻找最短路还要额外维护两个值——最短路数目和救援组数目和最大值

  • 怎么处理呢?

增加两个维护类型,那我们也额外开两个数组记录呗:

一个数组记录最短路数目;一个数组记录完整的最短路路径,然后就可以根据路径来单独计算该条最短路径上的救援组数目,最后比较得出最大救援组数目和

  • 怎么维护最短路径数目?

我们使用ans[i]来存储第i号节点的最短路径数目

  1. 在跑Dijkstra时,如果dis[v]>dis[x]+e[i].val那么ans[v]=ans[x],因为不是最短路所以直接继承上一个节点的最短路数目即可

  2. 如果dis[v]==dis[x]+e[i].val那么ans[v]+=ans[x],因为最短路长度相等,所以累加最短路数目

  • 怎么记录一条完整的最短路路径?

记录一条完整路径,那我们记录在路径上每一个点的前驱即可

需要特别注意的是:

  1. 因为在本题中点的前驱不一定只有一个,所以我们需要使用vector(也许有其他做法,这里不多赘述)

  2. 当更新了当前的最短路时,当前节点v的前驱应该先清空,然后再把前一个点x存入前驱

来讲讲原因:

  1. 因为存在多条最短路径,而每条最短路径经过的点是可能重复的(这里还不涉及到救援组数目最大值),所以记录点的前驱需要使用vector

  2. 如果最短路都更新了,那么前面存的前驱也就没有用了,所以需要清空

if(dis[v]>dis[x]+e[i].val) {
ans[v]=ans[x];
pre[v].clear();
pre[v].push_back(x);
dis[v]=dis[x]+e[i].val;
shan.push(make_pair(-dis[v],v));
}
else if(dis[v]==dis[x]+e[i].val) {
ans[v]+=ans[x];
pre[v].push_back(x);
}
  • 记录了路径,那怎么维护救援组和的最大值?

我们在跑完Dijkstra部分后,进入dfs然后遍历vector来“复原”每一条最短路径

dfs中有两个参数:第一个now指当前的点,第二个sum表示至今的救援组数目和

如果now到达了起点,就用num比较出最大值

inline void dfs(int now,int sum) {
if(now==s) {
num=max(num,sum);
return ;
}
for(vector<int>::iterator it=pre[now].begin();it!=pre[now].end();it++) {
dfs(*it,sum+a[*it]);
}
}

完整Code:

解题思路如上所示,现在给出完整代码如下:

#include <bits/stdc++.h>
using namespace std;
int n,m,s,u,v,w,t,tot,num,a[250010];
int dis[250010],vis[250010],head[250010],ans[250010];
vector<int> pre[250010];
priority_queue<pair<int,int> > shan; struct node {
int to,net,val;
} e[250010]; inline void add(int u,int v,int w) {
e[++tot].val=w;
e[tot].to=v;
e[tot].net=head[u];
head[u]=tot;
} inline void dijkstra(int s) {
fill(dis,dis+250010,20050206);
dis[s]=0;
ans[s]=1; //起点肯定有路径,所以初始值为1
shan.push(make_pair(0,s));
while(!shan.empty()) {
int x=shan.top().second;
shan.pop();
if(vis[x]) continue;
vis[x]=1;
for(register int i=head[x];i;i=e[i].net) {
int v=e[i].to;
if(dis[v]>dis[x]+e[i].val) { //更新最短路
ans[v]=ans[x];
pre[v].clear(); //一定要清空前驱,再压入x
pre[v].push_back(x);
dis[v]=dis[x]+e[i].val;
shan.push(make_pair(-dis[v],v)); //入队
}
else if(dis[v]==dis[x]+e[i].val) { //如果最短路长度相等
ans[v]+=ans[x]; //累加最短路数目
pre[v].push_back(x); //同样记录前驱
}
}
}
} inline void dfs(int now,int sum) { //遍历所有最短路径求最大救援组数目和
if(now==s) { //回溯到起点,更新答案
num=max(num,sum);
return ;
}
for(vector<int>::iterator it=pre[now].begin();it!=pre[now].end();it++) { //利用vector不断遍历前驱
dfs(*it,sum+a[*it]);
}
} int main() {
scanf("%d%d%d%d",&n,&m,&s,&t);
for(register int i=0;i<n;i++) {
scanf("%d",&a[i]);
}
for(register int i=1;i<=m;i++) {
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
dijkstra(s);
dfs(t,a[t]);
printf("%d %d",ans[t],num);
return 0;
}

最后,特别感谢一下RHL大佬对蒟蒻的指导qwq


最新文章

  1. [ASP.NET MVC 小牛之路]15 - Model Binding
  2. Unable to require openssl, install OpenSSL and rebuild ruby (preferred) or use non-HTTPS sources解决
  3. ligerui_ligerTree_002_利用JavaScript代码配置ligerTree节点
  4. adt-bundle-linux-x86_64-20131030下新建project提示找不到adb和R.java问题的解决
  5. dubbo源码分析三:consumer注册及生成代理对象
  6. TCP连接的状态分析
  7. 提高你开发效率的十五个Visual Studio 2010使用技巧
  8. C语言实现md5函数代码
  9. log.go 源码阅读
  10. git 重命名本地分支,并提交到远程
  11. MySQL事务提交过程(二)
  12. java学习-消息队列rabbitmq的组成
  13. LODOP弹出对话框获取保存文件的路径
  14. java 对象锁学习
  15. java-接口和抽象类的联系和区别。
  16. Linux_Nginx 安装
  17. 在软件webstorm中给img标签加入class报错显示错误selector matches unknow element
  18. Postgres中tuple的组装与插入
  19. PHP Web木马扫描器
  20. Linux sed命令用法

热门文章

  1. java实现第六届蓝桥杯表格计算
  2. XStrea学习手册
  3. vi命令总结
  4. 【asp.net core】7 实战之 数据访问层定义
  5. 温故知新-java多线程&amp;深入理解线程池
  6. mysql导入超大sql文件
  7. 谈谈Spring中的对象跟Bean,你知道Spring怎么创建对象的吗?
  8. vs2010静态编译qt5.1.0
  9. java 中有几种类型的流?
  10. Python的数据的基本类型