PAT(A)1003 Emergency
题目链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805523835109376
题意:计算最短路和最短路的线路数目已经最短路中点权值和的最大值
思路: 多条最短路的变式题,只需要多定义个数组来维护线路数目和点权值和,当松弛操作进行更新时对于d[y]==d[x]+len 情况也进行讨论和两个数组的数据更新。
代码:
dijkstra
#include<bits/stdc++.h>
using namespace std;
int n,m,s,t;
int a[505];
struct node{
int ne,v;
node(int _n,int _v):ne(_n),v(_v){}
};
vector<struct node> edge[1005];
int vis[1005]={0};
int d[1005];
int lennum[1005]={0};//线数目
int sum[1005]={0};//最大点权值
priority_queue<pair<int,int>> q;
void dijk(){
memset(d,0x3f,sizeof(d));
q.push(make_pair(0,s));
d[s]=0;
lennum[s]=1;
sum[s]=a[s];
while(q.size()){
int x=q.top().second;
q.pop();
if(vis[x])continue;
vis[x]=1;//注意dij中v数组的意思是是否已经确定为最小值,所以需要在弹出最小根堆时赋值为1
for(int i=0;i<edge[x].size();i++){
int len=edge[x][i].v;
int y=edge[x][i].ne;
if(d[y]>d[x]+len){
d[y]=d[x]+len;
lennum[y]=lennum[x];
sum[y]=sum[x]+a[y];
q.push(make_pair(-d[y],y));
}
else if(d[y]==d[x]+len){//多条最短路变式题 需要对本情况进行讨论和数据更新
lennum[y]+=lennum[x];
sum[y]=max(sum[x]+a[y],sum[y]);
}
}
}
cout<<lennum[t]<<" "<<sum[t];
}
int main (){
cin>>n>>m>>s>>t;
for(int i=0;i<n;i++)cin>>a[i];
int x,y,z;
for(int i=0;i<m;i++){
cin>>x>>y>>z;
edge[x].push_back(node(y,z));
edge[y].push_back(node(x,z));
}
dijk();
return 0;
}
SPFA
通过SPFA进行计算多条最短路径变式题时应该注意,统计最短路径条数时应该加一个set来维护,如果路径条数发生变化也应该加到队列中,对于其他统计则不需要。
#include<bits/stdc++.h>
using namespace std;
int n,m,s,t;
struct node{
int ne,w;
node(int _ne,int _w):ne(_ne),w(_w){}
};
vector<struct node>edge[1005];
int d[1005];
int a[1005];
int vis[1005]={0};
queue<int>q;
int lensum[1005]={0};
int wsum[1005]={0};
set<int> pre[1005];
const int INF=0x3fffffff;
void spf(){
fill(d,d+1005,INF);
d[s]=0;
q.push(s);
vis[s]=1;
lensum[s]=1;
wsum[s]=a[s];
set<int> ::iterator it;
while(!q.empty()){
int x=q.front();
vis[x]=0;//SPFA中vis数组定义为 当前是否在队列中
q.pop();
for(int i=0;i<edge[x].size();i++){
int y=edge[x][i].ne;
int len=edge[x][i].w;
if(d[y]>d[x]+len){
d[y]=d[x]+len;
if(!vis[y])
q.push(y);
vis[y]=1;
wsum[y]=wsum[x]+a[y];
lensum[y]=lensum[x];
pre[y].clear();
pre[y].insert(x);
}
else if(d[y]==d[x]+len){
if(wsum[x]+a[y]>wsum[y])wsum[y]=wsum[x]+a[y];
pre[y].insert(x);
lensum[y]=0;
for(it=pre[y].begin();it!=pre[y].end();it++){//由于SPFA是根据有所更新的点进行更新,所以很多点可能重复更新多次,则计算最短路径条数时需要定义一个set来保存连接到当前点的其他点,当出现等于情况时进行重新计算。
lensum[y]+=lensum[*it];
}
if(!vis[y]){ //注意这里 在SPFA中队列内为有更新的点 ,其中更新不光是d,最短路径条数进行更新了也要加到队列中,
q.push(y);
}
vis[y]=1;
}
}
}
cout<<lensum[t]<<" "<<wsum[t];
}
int main (){
cin>>n>>m>>s>>t;
for(int i=0;i<n;i++)cin>>a[i];
int x,y,z;
for(int i=0;i<m;i++){
cin>>x>>y>>z;
edge[x].push_back(node(y,z));
edge[y].push_back(node(x,z));
}
spf();
return 0;
}

浙公网安备 33010602011771号