P1119 灾后重建
灾后重建


思路:
-
理解Floyd的核心是:
最外层执行到k(还没进入内层循环)表示,只用[1,k-1]作为中转,\(i->j\) 的最短路
执行k时,意思是:尝试用新加入的k点,缩短 \(i->j\) 的距离
-
灾后重建:
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\) 的距离
-
为什么不需要再用\(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;
}
备注:距离我做完这道题已经过了好一会了,我的总结如果有误,欢迎指正

浙公网安备 33010602011771号