P1119 灾后重建(floyd进阶)

思路:这道题看n的范围很小(n<=200),显然就用floyd可以解决的问题,但又并不是简单的floyd算法,还是需要一些小小的变化。一开始我的思路是先跑一次弗洛伊德最短路,这样子显然复杂度很高,并且题目中的路径长度是时刻可能更新的,所以我们应该在修建的时候再跑最短路。可以用一个变量来记录修改的点,这样子就可以大幅度的优化。

代码如下

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
const int N=250;
int n,m,x,y,v,T;
int t[maxn];
int f[N][N];
int flag[N][N];
int xx,yy,tt;
int start;//动态变化的那个点
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&t[i]);
        f[i][i]=0;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            f[i][j]=1e9;
        }
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&v);
        f[x][y]=f[y][x]=v;
    }
    scanf("%d",&T);
    for(int o=1;o<=T;o++)
    {
        start=0;//Tle原因
        scanf("%d%d%d",&xx,&yy,&tt);
        while(t[start]<=tt&&start<n)
        {
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<n;j++)
                {
                    f[i][j]=min(f[i][start]+f[start][j],f[i][j]);
                }
            }
            start++;
        }
        if(f[xx][yy]==1e9||t[xx]>tt||t[yy]>tt)
        {
            printf("-1\n");
        }
        else
        {
            printf("%d\n",f[xx][yy]);
        }
    }
    return 0;
}

等等,但这样似乎只有30分,吸氧50 ,T了7个点

究其原因,是因为每次跑弗洛伊德的时候,start都是又从零开始枚举的,这样显然是没有必要的

所以我们就将他简单改一下

 

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
const int N=250;
int n,m,x,y,v,T;
int t[maxn];
int f[N][N];
int flag[N][N];
int xx,yy,tt;
int start;
int Read(){
    int X = 0 ; char ch = getchar() ;
    while(ch > '9' || ch < '0') ch = getchar() ;
    while(ch >= '0' && ch <= '9')
    X = (X << 1) + (X << 3) + (ch ^ 48), ch = getchar() ;
    return X ;
}
int main()
{
    n=Read(),m=Read();
    for(int i=0;i<n;i++)
    {
        t[i]=Read();
        f[i][i]=0;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            f[i][j]=1e9;
        }
    }
    for(int i=1;i<=m;i++)
    {
        x=Read();
        y=Read();
        v=Read();
        f[x][y]=f[y][x]=v;
    }
    T=Read();
    for(int o=1;o<=T;o++)
    {
        xx=Read(),yy=Read(),tt=Read();
        while(t[start]<=tt&&start<n)
        {
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<n;j++)
                {
                    f[i][j]=min(f[i][start]+f[start][j],f[i][j]);
                }
            }
            start++;
        }
        if(f[xx][yy]==1e9||t[xx]>tt||t[yy]>tt)
        {
            printf("-1\n");
        }
        else
        {
            printf("%d\n",f[xx][yy]);
        }
    }
    return 0;
}

 

因为修建的时候那个点都是一遍更新的,并且时间是单调递增的

所以只需要更新一遍就得了,那个动态的点就不用再次清零了。

 

上一篇:洛谷P1119 灾后重建(Floyd)


下一篇:图论&线性基(?)(8.12)