【最短路 计数 方案输出 点权和 多级】L2-001 紧急救援 (25 分)

【最短路 方案】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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值