暑训日记Day3 T4《路径》题解 (最短路)

该问题要求在给定的无向图中找出从起点S到终点T的所有最短路径,并计算每个点在关键路径上的情况。通过Dijkstra算法找到最短路径,然后判断哪些点在关键路径上。对于关键路径上的边,可以累加路径数量。最后输出每个点是否是关键点及其对应的路径数量。
摘要由CSDN通过智能技术生成

T4 路径

【问题描述】

Y Y Y有一个 n n n 个点, m m m 条边的无向图,规定起点 S S S 和终点 T T T(保证 S / T S/T S/T 联通),一个人从 S S S T T T 的任意一条最短路都算一条关键路径,而关键路径上的点被称作关键点。假设每个单位 时间能够移动 1 的长度,你需要完成一下任务:对于第 i i i 个点,如果其不是关键点,请输出 “ 0 0 0”;如果是关键点,设从 S S S 走最短路到点 i i i 的时刻为 T i T_i Ti( 0 0 0 时刻从 S S S 出发),输出在时间为 T i T_i Ti 时,这个人走关键路径可以到达的不同位置的数量。(注:这个人不一定在节点上,可能 在边上,比如一条长度为 7 7 7 的边,他可以在长度为 1 , 2 , 3 , 4 , 5 , 6 1,2,3,4,5,6 1,2,3,4,5,6 的地方,而不仅限于两个端点)。 你轻易地就解决了这道题。

【输入格式】

第一行为用空格隔开的三个正整数 n , S , T n,S,T nST

第二行为一个正整数 m m m。 接下来 m m m 行每行三个正整数 x , y , z , x,y,z, xyz表示 x x x y y y 之间有一条长度为 z z z 的无向边。

【输出格式】

输出共 n n n 行。

i i i 行请输出对应第 i i i 个点所应输出信息。

【输入样例】

4 1 4
4
1 2 3
1 3 4
2 4 4
3 4 3

【输出样例】

1
2
2
1

【数据范围】

对于前 20%的数据,$n ≤ 10 $

对于另外 20%的数据,保证是一棵树

对于 100%的数据, n ≤ 2000 , m ≤ 2 ∗ 1 0 5 , z ≤ 106 n ≤ 2000,m ≤ 2*10^5,z ≤ 106 n2000,m2105,z106

【题解】

先跑出最短路,对于在关键路上的边的两个端点 u , v u,v u,v ( d i s t [ u ] < d i s t [ v ] ) (dist[u]<dist[v]) (dist[u]<dist[v]),可以直接把 d i s t [ u ] − > d i s t [ v ] dist[u]->dist[v] dist[u]>dist[v]区间中的答案都加一。输出第 i i i个点的答案时,直接输出 d i s t [ i ] dist[i] dist[i]所对应的答案。
要说图论这题放T4其实还好,虽然当时我没有打出来(真是 f w fw fw
不想再自己敲了,下面是标程。我觉得 h a s h hash hash可以用 p b d s pbds pbds里的,还有 s p f a spfa spfa不如 d i j k s t r a dijkstra dijkstra

#include<bits/stdc++.h>
using namespace std;
const int Mod=131071;
int N,S,T;
int M;
int dist[2010]={0};
int st=1,en=0;
int num=0;
int HASH[2010]={0};
int dui[131100]={0};
int D[2010]={0};
int Sum[2010]={0};
int Sp=0;
struct bian_{
	int st;
	int to;
	int next;
	int dis;
}bian[400010]={{0,0,0,0}};
int First[2010]={0};
int vis[2010]={0};
void Add(int p,int q,int r,int k){
	bian[k].next=First[p];
	bian[k].st=p;
	bian[k].to=q;
	bian[k].dis=r;
	First[p]=k;
	return;
}
void SPFA(){
	memset(dist,0x3f3f3f3f,sizeof(dist));
	dui[++en]=S;
	dist[S]=0;
	num=1;
	for(;num>0;){
		int u=dui[st];
		st=(st&Mod)+1;
		HASH[u]=0;num--;
		for(int i=First[u];i!=0;i=bian[i].next){
			int v=bian[i].to;
			if(dist[v]>dist[u]+bian[i].dis){
				dist[v]=dist[u]+bian[i].dis;
				if(HASH[v]==0){
					HASH[v]=1;
					if(dist[v]<dist[dui[st]]){
						st=((st+Mod-1)&Mod)+1;
						dui[st]=v;
					}
					else{
						en=(en&Mod)+1;
						dui[en]=v;
					}
					num++;
				}
			}
		}
	}
	return;
}
int Find(int k){
	for(int l=1,r=Sp;l<=r;){
		int mid=(l+r)>>1;
		if(D[mid]==k) return mid;
		if(D[mid]<k) l=mid+1;
		else r=mid-1;
	}
	return 0;
}
int main(){
	freopen("path.in","r",stdin);
	freopen("path.out","w",stdout);
	scanf("%d%d%d",&N,&S,&T);
	scanf("%d",&M);
	for(int i=1;i<=M;i++){
		int p,q,r;
		scanf("%d%d%d",&p,&q,&r);
		Add(p,q,r,(i<<1)-1);
		Add(q,p,r,i<<1);
	}
	SPFA();
	for(int i=1;i<=N;i++)
		D[++Sp]=dist[i];
	sort(D+1,D+N+1);
	Sp=1;
	for(int i=2;i<=N;i++)
		if(D[i]!=D[i-1])
			D[++Sp]=D[i];
	for(int i=Sp+1;i<=N;i++) D[i]=0;
	en=1;
	dui[1]=T;
	for(int i=1;i<=en;i++){
		int u=dui[i];
		for(int p=First[u];p!=0;p=bian[p].next){
			int v=bian[p].to;
			if(dist[u]==dist[v]+bian[p].dis){
				int L=Find(dist[v]),R=Find(dist[u]);
				vis[v]=vis[u]=1;
				Sum[L+1]++,Sum[R]--;
				if(HASH[v]==0)
					dui[++en]=v,HASH[v]=1;
			}
		}
	}
	for(int i=1;i<=Sp;i++)
		Sum[i]+=Sum[i-1];
	for(int i=1;i<=N;i++)
		if(vis[i]==1)
			Sum[Find(dist[i])]++;
	for(int i=1;i<=N;i++){
		int p=Find(dist[i]);
		printf("%d\n",Sum[p]*vis[i]);
	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}

看完请留下你的痕迹 t h x thx thx

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值