题目大意
在一张无向网中,每个结点都有自己的权值,每条路径也有对应的权值,求源点s到终点d的最短路径,在保证最短路径的情况下求出经过结点权值的最大值,并输出最短路径经过的结点编号。
解题思路
这是一道很明显的最短路径的模板题。但要注意题目要求计算出最短路径的数量和经过的路径。
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f3f3f3f
#define Max_N 500+5
#define mod 10000019
using namespace std;
typedef pair<int,int>P;//first是最短距离,second是顶点编号
typedef long long ll;
typedef unsigned long long ull;
struct endg
{
int to;
int cost;
};//邻接表存图
int pre[Max_N];//用来保存每个结点的前驱
vector<endg>G[Max_N];//无向图
int d[Max_N], maxval[Max_N],pathcount[Max_N];//最短距离,最大权值和,路径数量
int number[Max_N];//每个结点的权值
void dijk(int s,int n)
{
priority_queue<P,vector<P>,greater<P> >que;//自定义优先队列
fill(d,d+n+1,INF);//初始化所有结点的最短距离为无穷大
d[s]=0;//到源点的距离为0
pathcount[s]=1;//到源点的路径数量为1
maxval[s]=number[s];
que.push(P(0,s));
while(!que.empty())
{
P p=que.top();
que.pop();
int v=p.second;
if(d[v]<p.first)
continue;//当取出来的距离不是最短距离就丢弃
for(int i=0;i<G[v].size();i++)//遍历顶点v连接的所有结点
{
endg e=G[v][i];
if(d[e.to]>d[v]+e.cost)//如果最短距离可以更小则更新
{
d[e.to]=d[v]+e.cost;
pre[e.to]=v;
maxval[e.to]=maxval[v]+number[e.to];
pathcount[e.to]=pathcount[v];
que.push(P(d[e.to],e.to));
}
else if(d[e.to]==(d[v]+e.cost))//如果相等,在更新路径数量
{
pathcount[e.to]+=pathcount[v];
if(maxval[e.to]<maxval[v]+number[e.to])
//在两条路径中选择最大权值和的那条
{
maxval[e.to]=maxval[v]+number[e.to];
pre[e.to]=v;
}
}
}
}
}
int main(int argc, char const *argv[])
{
int n,m,s,d;
//freopen("data.txt","r",stdin);
cin>>n>>m>>s>>d;
memset(pre,-1,sizeof(pre));
for(int i=0;i<n;i++)
{
cin>>number[i];
}
for(int i=0;i<m;i++)
{
int a,b,c;
cin>>a>>b>>c;
endg mid1={b,c};
endg mid2={a,c};
G[a].push_back(mid1);//无向图
G[b].push_back(mid2);//无向图
}
dijk(s,n);
cout<<pathcount[d]<<" "<<maxval[d]<<endl;
vector<int>path;
for(;d!=-1;d=pre[d])
{
path.push_back(d);
}
reverse(path.begin(),path.end());
for(int i=0;i<path.size();i++)
{
if(i)
cout<<" ";
cout<<path[i];
}
cout<<endl;
return 0;
}
总结
自我感觉这道题有点dp的味道,用数组去存每个结点的信息,在求最短路径的过程中不断去更新。