zoukankan      html  css  js  c++  java
  • P1119 灾后重建 题解

    前置芝士:

    我的Floyd基础知识讲解


    说白了,Floyd本质上就是一个dp:

    K为外层状态,i和j为内层枚举。Floyd完整状态其实是:(f[k][i][j])表示以前K个点为转移点(即编号为1~k的点可以被用来松弛),从(i)(j)的最短路径。

    每条最短路径都是以k为基础的,对于未枚举进k的点将不被考虑进最短路径的松弛,k也就作为整个图的最短路径的前提条件,那么自然作为最外层状态转移。

    考虑这道题:

    给你一张无向图,给你每一个节点的信息t表示当前节点在时间为t以及以后可以到达。

    翻译一下,也就是可以考虑进最短路的松弛。

    朴素想法,对于每个t,我们可以枚举每一个结点,如果结点的(t>)当前询问的时间,将不被考虑进图中。每一次询问在重新建完图后跑一边Floyd,并在判断起点村庄s到终点l能否到达,如果能到达输出即可。

    很明显,T的死死的。每次跑一遍floyd实在是太浪费了时间,而且题目中的数据是递增的。出题人给你的优化条件你怎么能不用呢。

    k表示考虑了1~n的节点作为可松弛点,也就是说:编号1到n的节点都能够到达。

    换句话说,1到n节点满足了被加入最短路集合的条件。

    对于这道题,从暴力思路可以看出,一个节点被加入最短路集合的条件就是当前节点的t值小于等于询问的时间t。而出题人给你的t是单调的。那么,我们设上一次询问的时间为(t_{0}),这一次询问的时间为(t_{1}),以t为floyd最外层状态k,对于(t_{0})之前的k我们就不必再跑一遍了,从上一次能够到达的编号为now的节点开始往后判断节点的t是否小于询问的t,直到大于询问的t为止。

    原因很好理解,节点的t随着编号的上升而上升,而询问的t又上升,那么考虑过的节点一定满足加入最短路集合的条件,也就不用再跑一遍Floyd((n^2))的部分了。

    核心代码:

    q=read();
    	while(q--)
    	{
    		u=read(),v=read(),w=read();
    		while(now<n&&a[now]<=w)
    		{
    			dp(now);//now节点就可以被加入可用来松弛的节点的集合,跑一边floyd
    			now++;//考虑编号更大的,t值更大的结点。
    		}
    	}
    	\Floyd部分
    inline void dp(int now)
    {
    	for(int i=0;i<n;i++)
    		for(int j=0;j<n;j++)
    		{
    			dis[i][j]=min(dis[i][j],dis[i][now]+dis[now][j]);
    		}
    }
    

    全部代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    #define re register
    using namespace std;
    const int N=201;
    inline int read()
    {
    	int x=0,f=1; char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    int n,m,a[N],u,w,v,q,judge=-1,dis[N][N],now;
    inline void add(int from,int to,int w)
    {
    	dis[from][to]=dis[to][from]=w;
    }
    inline void dp(int now)
    {
    	for(int i=0;i<n;i++)
    		for(int j=0;j<n;j++)
    		{
    			dis[i][j]=min(dis[i][j],dis[i][now]+dis[now][j]);
    		}
    }
    int main()
    {
    	n=read(),m=read();
    	for(int i=0;i<n;i++)
    		for(int j=0;j<n;j++)
    			dis[i][j]=1e9+7;
    	for(int i=0;i<n;i++)
    	{
    		a[i]=read();
    	}
    	for(int i=1;i<=m;i++)
    	{
    		u=read(),v=read(),w=read();
    		add(u,v,w);
    	}
    	q=read();
    	while(q--)
    	{
    		u=read(),v=read(),w=read();
    		while(now<n&&a[now]<=w)
    		{
    			dp(now);
    			now++;
    		}
    		if(a[u]>w||a[v]>w)printf("%d
    ",judge);
    			else
    			{
    				if(dis[u][v]==1e9+7)printf("%d
    ",judge);
    				else printf("%d
    ",dis[u][v]);
    			}
    	}
    	return 0;
    }
    
    

    希望看完这篇博文后能够加深各位对Floyd的理解!

    完结撒花

  • 相关阅读:
    leetcode 268. Missing Number
    DBSCAN
    python二维数组初始化
    leetcode 661. Image Smoother
    leetcode 599. Minimum Index Sum of Two Lists
    Python中的sort() key含义
    leetcode 447. Number of Boomerangs
    leetcode 697. Degree of an Array
    滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(1月3日)
    北京Uber优步司机奖励政策(1月2日)
  • 原文地址:https://www.cnblogs.com/lbssxz/p/13357239.html
Copyright © 2011-2022 走看看