CF144D

思路:

天真的想法是把每条边上都建上 \(w-1\) 个点然后跑最短路
但是边权总和很大,显然不能这么做。

考虑对原图求单源最短路,记 \(s\) 到 \(u\) 的最短路为 \(d_u\),可以直接统计在点上的答案。

考虑如何统计在边上的答案,显然每条边至多有 \(2\) 个。

记这个边的两端是 \(u\),\(v\),那么分类讨论从 \(u\) 走过去还是从 \(v\) 走过去,假设从 \(u\) 走,显然需要往边里走 \(l-d_u\),那么这个位置走到 \(v\) 再走到 \(s\) 的距离是 \(w-l+d_u+d_v\),判断是否大于 \(l\) 即可。

注意考虑边上只有一个点的情况,也就是往那边走都是 \(l\)。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
struct node
{
	int to,v;
	bool operator<(const node &o) const
	{
		return v>o.v;
	}
};
int x[(int)(1e5+10)],y[(int)(1e5+10)],w[(int)(1e5+10)];
int dis[(int)(1e5+10)],n,s,m;
vector<node>edge[(int)(1e5+10)];
priority_queue<node>q;
bool v[(int)(1e5+10)];
signed main()
{
	cin>>n>>m>>s;
	for(int i=1;i<=n;i++) dis[i]=INT_MAX;
	for(int i=1;i<=m;i++)
	{
		int u,v,d;cin>>u>>v>>d;
		x[i]=u,y[i]=v,w[i]=d;
		edge[u].push_back((node){v,d});
		edge[v].push_back((node){u,d});
	}
	dis[s]=0;
	q.push((node){s,0});
	while(q.size())
	{
		int u=q.top().to;
		q.pop();
		if(v[u]) continue;
		v[u]=1;
		for(int i=0;i<edge[u].size();i++)
		{
			if(dis[edge[u][i].to]>dis[u]+edge[u][i].v)
			{
				dis[edge[u][i].to]=dis[u]+edge[u][i].v;
				q.push((node){edge[u][i].to,dis[edge[u][i].to]});
			}
		}
	}
	int cnt=0,l;
	cin>>l;
	for(int i=1;i<=n;i++)
	{
		cnt+=(dis[i]==l);
	}
	for(int i=1;i<=m;i++)
	{
		if(dis[x[i]]+w[i]-l+dis[y[i]]==l&&dis[y[i]]<l&&dis[x[i]]<l)
		{
//			cout<<"case 1: "<<i<<"\n";
			cnt++;
			continue;
		}
		if(dis[x[i]]+w[i]-l+dis[y[i]]>l&&dis[x[i]]<l)
		{
//			cout<<"case 2: "<<i<<"\n";
			cnt++;
		}
		if(dis[x[i]]+w[i]-l+dis[y[i]]>l&&dis[y[i]]<l)
		{
//			cout<<"case 3: "<<i<<"\n";
			cnt++;
		}
	}
	cout<<cnt<<"\n";
}
上一篇:浅谈费用流


下一篇:基础最短路算法讲解