题解 Luogu P1608.路径统计

欢迎访问 My Luogu Space

【题目大意】

有一张 n (n <= 2000) 个点 m (m <= n*(n-1)/2) 条边的有向图,每个边的边权为 c (c<=10) 。请求出从 1 到 n 的最短路以及最短路的条数。


【题解】

spfa / dij

直接用 spfa 或者 dij 求最短路(本题解采用 spfa),在求最短路的时候多统计一个数组 cnt[i] 表示从 1 到 i 的最短路有几条。

初始化 cnt[1] = 1,每次更新多增加一下操作:

  1. 如果 dis[x]+w[i] == dis[e[i]],那么 cnt[e[i]] += cnt[x];
  2. 如果 dis[x]+w[i] < dis[e[i],那么 dis[e[i]] = dis[x]+w[i], cnt[e[i]] = cnt[x];

并且每次更新完一个点之后,需要把当前点的 cnt[i] 清零,否则会重复计算。


【代码】

#include <bits/stdc++.h>
using namespace std;
const int MN = 2000+10;
const int INF = 0x3f3f3f3f;

int n, m, dis[MN], cnt[MN], f[MN];
int t[MN][MN];

int spfa(){
	memset(dis, INF, sizeof dis);
	queue<int> Q; Q.push(1);
	dis[1] = 0, cnt[1] = 1;
	while(!Q.empty()){
		int x = Q.front(); Q.pop();
		f[x] = 0;
		if(x==n) continue;
		for(int i=1; i<=n; ++i){
			if(dis[x]+t[x][i]==dis[i]) 
				cnt[i] += cnt[x];
			else if(dis[x]+t[x][i]<dis[i]){
				dis[i] = dis[x]+t[x][i];
				cnt[i] = cnt[x];
			}
			if(cnt[i] && !f[i])
				f[i] = 1, Q.push(i);
		}
		cnt[x] = 0;
	}
	return dis[n];
}
int main(){
	scanf("%d%d", &n, &m);
	memset(t, INF, sizeof t);
	for(int i=1; i<=m; ++i){
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		t[a][b] = min(t[a][b], c);
	}
	if(spfa()==INF) puts("No answer");
	else printf("%d %d", dis[n], cnt[n]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值