头像

欢迎来到我的博客

分享题解与总结

P1119 灾后重建

灾后重建

屏幕截图 2026-03-15 192602

屏幕截图 2026-03-15 192620

思路:

  1. 理解Floyd的核心是:

    最外层执行到k(还没进入内层循环)表示,只用[1,k-1]作为中转,\(i->j\) 的最短路

    执行k时,意思是:尝试用新加入的k点,缩短 \(i->j\) 的距离

  2. 灾后重建:

    q表示当前询问,p指向本次询问之前,第一个尚未重建完成的村庄\(a_s\) (满足\(t[a]<d_{p-1}\))

    第q次询问,由于\(d_{p-1}<d_p\),所以又有一些村庄重建完成\(a_s,a_{s+1},...,a_{l}\)

    \(a_s,a_{s+1},...,a_{l}\)更新 \(i->j\) 的距离

  3. 为什么不需要再用\(a_1,a_2,...,a_{s-1}\)更新一遍 \(i->j\) 的最短距离?

    你可以理解为: \(i->j\) 的最短路已经可以中转\(a_1,a_2,...,a_{s-1}\)了,\(a_s,a_{s+1},...,a_{l}\)不过是增加了一些中转站

    如果再使用\(a_1,a_2,...,a_{s-1}\)更新一遍 \(i->j\) 的最短距离,相当于有考虑一遍:用\(a_1,a_2,...,a_{s-1}\)作为中转站,

    会不会使总路程变小

    所以,\(a_s,a_{s+1},...,a_{l}\)的更新相当于是:将这些点纳入为了缩短 \(i->j\) 的距离的中转站集合中

代码:

int n,m,t[N],x,y,w,d,q;
int dis[N][N],p;

void floyd_warshall(int starti,int endi,int timei)
{
	int i,j;
	for(;p<n&&t[p]<=timei;++p)
	{
		for(i=0;i<n;++i){
			for(j=0;j<n;++j){
				if(dis[i][p]!=INF&&dis[p][j]!=INF&&dis[i][p]+dis[p][j]<dis[i][j])
					dis[i][j]=dis[i][p]+dis[p][j];
			}
		}
	}
	if(t[starti]>timei||t[endi]>timei||dis[starti][endi]==INF) cout<<-1<<'\n';
	else cout<<dis[starti][endi]<<'\n';
}

int main()
{
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>m;
	for(int i=0;i<n;++i){
		for(int j=0;j<n;++j){	
			if(i!=j) dis[i][j]=INF;
			else dis[i][j]=0;
		}
	}
	for(int i=0;i<n;++i){
		cin>>t[i];
	}
	for(int i=0;i<m;++i){
		cin>>x>>y>>w;
		dis[x][y]=w;
		dis[y][x]=w;
	}
	cin>>q;
	while(q--){
		cin>>x>>y>>d;
		floyd_warshall(x,y,d);
	}
	return 0;
}

备注:距离我做完这道题已经过了好一会了,我的总结如果有误,欢迎指正

posted @ 2026-03-15 19:54  king_steph1209  阅读(1)  评论(0)    收藏  举报