PAT 团体程序设计天梯赛-练习集 L2-001. 紧急救援 【dijkstra】

时间:2023-02-13 10:52:58

题目链接

http://blog.csdn.net/tc_to_top/article/details/51427223

思路

题意是求个最短路,要求路径长度和最短的前提下,点权和最大,并求出长度相等的最短路有几条,并输出路径,是dijkstra的灵活运用。

这种题好像写过很多遍了,但这次还是不能一次过,调试了半天。

点权和最大很好解决,给dis加一个属性就可以了。

输出最短路径,可以用一个数组记录每个点的前驱。

最短路有几条卡了挺久,方法是对每个点设一个cnt记录到这个点的最短路径有几条,
然后每次更新dis,如果路径长相等,就加上前驱点的cnt,否则如果新路径更短,就置为前驱点的cnt。

AC代码

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;

const int INF=0x3f3f3f3f;
int w[600];
int g[600][600];
int n,m,s,d;
struct node
{
node()
{
l=INF;
w=0;
}
node(int _l, int _w)
{
w=_w;
l=_l;
}
bool friend operator < (node a, node b)
{
if(a.l==b.l)
return a.w>b.w;
return a.l<b.l;
}
int w,l;
}dis[600];
bool vis[600];
int cnt[600];
int pre[600];
void dijkstra(int start)
{
dis[start].l=0;
dis[start].w=w[start];
for(int i=0 ; i<n ; ++i)
{
node min_node(INF,0);
int u=-1;
for(int j=0 ; j<n ; ++j)
{
if(vis[j]==0 && dis[j]<min_node)
{
min_node=dis[j];
u=j;
}
}
for(int v=0 ; v<n ; ++v)
{
if(vis[v]==0 && g[u][v]<INF)
{
node new_dis=node(dis[u].l+g[u][v], dis[u].w+w[v]);
if(new_dis.l==dis[v].l)
{
cnt[v]+=cnt[u];
}
if(new_dis.l<dis[v].l)
{
cnt[v]=cnt[u];
}
if(new_dis<dis[v])
{
dis[v]=new_dis;
pre[v]=u;
}
}
}
vis[u]=1;
}
}
void init()
{
for(int i=0 ; i<600 ; ++i) cnt[i]=1;
memset(g,INF,sizeof g);
memset(pre,-1,sizeof pre);
}
int main()
{
init();
scanf("%d%d%d%d",&n,&m,&s,&d);
for(int i=0 ; i<n ; ++i)
{
scanf("%d",&w[i]);
}
for(int i=0 ; i<m ; ++i)
{
int u,v,l;
scanf("%d%d%d",&u,&v,&l);
g[u][v]=g[v][u]=l;
}
dijkstra(s);

int t=d;
vector<int>ans;
while(pre[t]!=-1)
{
ans.push_back(t);
t=pre[t];
}
ans.push_back(s);

printf("%d %d\n",cnt[d], dis[d].w);
for(int i=ans.size()-1 ; i>=0 ; --i)
{
if(i==(int)ans.size()-1)printf("%d",ans[i]);
else printf(" %d",ans[i]);
}
printf("\n");
return 0;
}