【最短路 方案】L2-001 紧急救援 (25 分)
题目
思路
看到fjy大佬又在疯狂刷题了,蒟蒻鱼竿也准备水一发
首先瞅瞅数据范围
N 2 500
M (不给数据范围是屑,假装N*N?)
道路长度均为整数且不超过500(按照常识是非负图)
单源最短路不过这个数据范围,貌似Floyd也可以莽一莽?hh
最短路 | 时间复杂度 |
---|---|
dijkstra 朴素 | O ( n 2 ) O(n^2) O(n2) |
dijkstra 堆优化 | O ( m l o g m ) O(mlogm) O(mlogm) |
SPFA | 最坏 O ( n m ) , 一 般 远 远 比 这 个 好 O(nm),一般远远比这个好 O(nm),一般远远比这个好 |
由于fjy大佬已经写过dijkstra的解法(虽然貌似复杂度写错了hh),我这蒟蒻就写一下SPFA解法吧
感觉是道缝合题目
单源最短路+最短路计数+路径输出+点权和最大
代码
蜜汁错误解法,希望有大佬帮忙找找错,目前确定的是最短路计数有问题
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
//#define MULINPUT
/*DATA & KEY
N 2 500
W 0 500
M ?500
wi 0 500
*/
int T;
int n,m,S,D;
const int N=505,M=N*N;
int h[N],e[M],ne[M],w[M],p[M],idx;
bool st[N];
int dist[N],ans[N],people[N],pre[N];
//dist起点S到i的最短距离,ans存起点S到i最短路径数,people存每个城市人数,pre存路径前驱
vector<int>path;//最短路径
void add(int a,int b,int c)//向前星
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void spfa()
{
memset(dist,0x3f,sizeof dist);
memset(pre,-1,sizeof pre);
dist[S]=0,ans[S]=1,people[S]=p[S];
pre[S]=-1;
queue<int>q;
q.push(S);st[S]=1;
while(q.size())
{
int t=q.front();q.pop();
st[t]=0;
for(int i=h[t];~i;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[t]+w[i])//发现更短路
{
dist[j]=dist[t]+w[i];
pre[j]=t;
ans[j]=ans[t];
people[j]=people[t]+p[j];
if(!st[j])//更新加入节点
{
q.push(j);
st[j]=1;
}
}
else if(dist[j]==dist[t]+w[i])//发现等长路
{
ans[j]+=ans[t];
if(people[j]<people[t]+p[j])
{
people[j]=people[t]+p[j];
pre[j]=t;
if(!st[j])//更新加入节点
{
q.push(j);
st[j]=1;
}
}
}
}
}
for(int i=D;~i;i=pre[i])path.push_back(i);
}
void solve(int C)
{
//NEW DATA CLEAN
//NOTE!!!
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
memset(h,-1,sizeof h);
cin>>n>>m>>S>>D;
for(int i=0;i<n;i++)cin>>p[i];
while(m--)
{
int a,b,c;cin>>a>>b>>c;
add(a,b,c),add(b,a,c);
}
spfa();
cout<<ans[D]<<" "<<people[D]<<endl;
int siz=path.size();
for(int i=siz-1;i>=0;i--)
{
cout<<path[i];
if(i)cout<<" ";
}
}
int main()
{
#ifdef MULINPUT
scanf("%d",&T);
for(int i=1;i<=T;i++)solve(i);
#else
solve(1);
#endif
return 0;
}
DFS实现最短路计数
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
//#define MULINPUT
/*DATA & KEY
N 2 500
W 0 500
M ?500
wi 0 500
*/
int T;
int n,m,S,D;
const int N=505,M=N*N;
int h[N],e[M],ne[M],w[M],p[M],idx;
bool st[N],vis[N];
int dist[N],people[N],pre[N];
//dist起点S到i的最短距离,people存每个城市人数,pre存路径前驱
vector<int>path;//最短路径
void add(int a,int b,int c)//向前星
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int ans;
void dfs(int u)
{
if(u==D)
{
ans++;return;
}
for(int i=h[u];~i;i=ne[i])
{
int j=e[i];
if(!vis[j]&&dist[j]==dist[u]+w[i])
{
vis[j]=1;
dfs(j);
vis[j]=0;
}
}
}
void spfa()
{
memset(dist,0x3f,sizeof dist);
memset(pre,-1,sizeof pre);
dist[S]=0,people[S]=p[S];
pre[S]=-1;
queue<int>q;
q.push(S);st[S]=1;
while(q.size())
{
int t=q.front();q.pop();
st[t]=0;
for(int i=h[t];~i;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[t]+w[i])//发现更短路
{
dist[j]=dist[t]+w[i];
pre[j]=t;
people[j]=people[t]+p[j];
if(!st[j])//更新加入节点
{
q.push(j);
st[j]=1;
}
}
else if(dist[j]==dist[t]+w[i])//发现等长路
{
if(people[j]<people[t]+p[j])
{
people[j]=people[t]+p[j];
pre[j]=t;
if(!st[j])//更新加入节点
{
q.push(j);
st[j]=1;
}
}
}
}
}
for(int i=D;~i;i=pre[i])path.push_back(i);
}
void solve(int C)
{
//NEW DATA CLEAN
//NOTE!!!
memset(h,-1,sizeof h);
scanf("%d%d%d%d",&n,&m,&S,&D);
for(int i=0;i<n;i++)scanf("%d",&p[i]);
while(m--)
{
int a,b,c;scanf("%d%d%d",&a,&b,&c);
add(a,b,c),add(b,a,c);
}
spfa();
dfs(S);
printf("%d %d\n",ans,people[D]);
int siz=path.size();
for(int i=siz-1;i>=0;i--)
{
printf("%d",path[i]);
if(i)printf(" ");
}
}
int main()
{
#ifdef MULINPUT
scanf("%d",&T);
for(int i=1;i<=T;i++)solve(i);
#else
solve(1);
#endif
return 0;
}