P1119 floyd

最开始看错数据了没看到Q = 100 是50%的数据以为跑q遍floyd能过,结果只有30,其他全t

1、要注意题目中的条件,挖掘一些性质

2、本题的另一个关键的是要对floyd的过程原理比较熟悉,floyd一共有三重循环,第一重循环相当于枚举的决策,也就是能从那个点转移过来,k就是这个中转站,另外两重循环是枚举的状态

3、我们观察到每个村庄的重建时间是递增的,并且询问的时间也是递增或保持不变,所以我们可以在读入每个询问的时间时,看一下是否存在中转站,在这个时间已经建好,并且可以去更新其他点,我们找到所以这样的点去更新,然后cur不用回去,因为询问的时间也是递增的,只需要在读入下一个询问后,查看是否有新的中转点可以去更新其他点即可。

4、经过上面的分析我们可以知道我们只需要跑一遍floyd即可,因为只有满足的中转点才会被用,时间复杂度为O(n^3)

附上floyd的板子

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 210, INF = 1e9;

int n, m, Q;

int d[N][N];

void Floyd()
{
    for(int k = 1; k <= n; k ++)
        for(int i = 1; i <= n; i ++)
         for(int j = 1; j <= n; j ++)
            //要取一下最小值这个写的时候老是忘记
            d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}

int main()
{
    cin >> n >> m >> Q;
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= n; j ++)
            if(i == j)  d[i][j] = 0;
            else    d[i][j] = INF;

    for(int i = 0; i < m; i ++)
    {
        int a, b, w; cin >> a >> b >> w;
        d[a][b] = min(d[a][b], w);
     }

    Floyd();

    while(Q --)
    {
        int a, b; cin >> a >> b;
        if(d[a][b] > INF / 2)   puts("impossible");
        else    cout << d[a][b]<<endl;;
    }

    return 0;
}

灾后重建

题目背景

B 地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路造成什么影响。但是在村庄重建好之前,所有与未重建完成的村庄的公路均无法通车。换句话说,只有连接着两个重建完成的村庄的公路才能通车,只能到达重建完成的村庄。

题目描述

给出 B 地区的村庄数 \(N\),村庄编号从 \(0\)\(N-1\),和所有 \(M\) 条公路的长度,公路是双向的。并给出第 \(i\) 个村庄重建完成的时间 \(t_i\),你可以认为是同时开始重建并在第 \(t_i\) 天重建完成,并且在当天即可通车。若 \(t_i\)\(0\) 则说明地震未对此地区造成损坏,一开始就可以通车。之后有 \(Q\) 个询问 \((x,y,t)\),对于每个询问你要回答在第 \(t\) 天,从村庄 \(x\) 到村庄 \(y\) 的最短路径长度为多少。如果无法找到从 \(x\) 村庄到 \(y\) 村庄的路径,经过若干个已重建完成的村庄,或者村庄 \(x\) 或村庄 \(y\) 在第 \(t\) 天仍未重建完成,则需要返回 -1

输入格式

第一行包含两个正整数\(N,M\),表示了村庄的数目与公路的数量。

第二行包含\(N\)个非负整数\(t_0, t_1,…, t_{N-1}\),表示了每个村庄重建完成的时间,数据保证了\(t_0 ≤ t_1 ≤ … ≤ t_{N-1}\)

接下来\(M\)行,每行\(3\)个非负整数\(i, j, w\)\(w\)为不超过\(10000\)的正整数,表示了有一条连接村庄\(i\)与村庄\(j\)的道路,长度为\(w\),保证\(i≠j\),且对于任意一对村庄只会存在一条道路。

接下来一行也就是\(M+3\)行包含一个正整数\(Q\),表示\(Q\)个询问。

接下来\(Q\)行,每行\(3\)个非负整数\(x, y, t\),询问在第\(t\)天,从村庄\(x\)到村庄\(y\)的最短路径长度为多少,数据保证了\(t\)是不下降的。

输出格式

\(Q\)行,对每一个询问\((x, y, t)\)输出对应的答案,即在第\(t\)天,从村庄\(x\)到村庄\(y\)的最短路径长度为多少。如果在第t天无法找到从\(x\)村庄到\(y\)村庄的路径,经过若干个已重建完成的村庄,或者村庄x或村庄\(y\)在第\(t\)天仍未修复完成,则输出\(-1\)

样例 #1

样例输入 #1

4 5
1 2 3 4
0 2 1
2 3 1
3 1 2
2 1 4
0 3 5
4
2 0 2
0 1 2
0 1 3
0 1 4

样例输出 #1

-1
-1
5
4

提示

对于\(30\%\)的数据,有\(N≤50\)

对于\(30\%\)的数据,有\(t_i= 0\),其中有\(20\%\)的数据有\(t_i = 0\)\(N>50\)

对于\(50\%\)的数据,有\(Q≤100\)

对于\(100\%\)的数据,有\(N≤200\)\(M≤N \times (N-1)/2\)\(Q≤50000\),所有输入数据涉及整数均不超过\(100000\)

#include <iostream>
#include <cstring>
using namespace std;
const int N = 210, INF = 2e9;

long long  d[N][N], a[N];
bool st[N];
int n, m;

inline void floyd(int k)
{
    for(int i = 0; i < n; ++ i)
        for(int j = 0; j < n; ++ j)
        if(d[i][j] > d[i][k] + d[k][j]) 
            d[i][j] = d[i][k] + d[k][j];
            
}

int main()
{   
    // freopen("1.in.txt", "r", stdin);
    cin >> n >> m;
    for(int i = 0; i < n; ++ i) cin >> a[i];
    for(int i = 0; i < n; ++ i)
        for(int j = 0; j < n; ++ j)
        {
            if(i == j)  d[i][i] = 0;
            d[i][j] = INF;
        }
            
    for(int k = 0; k < m; ++ k)
    {
        int a, b ,c; cin >> a >> b >> c;
        d[a][b] = d[b][a] = c;
    }
 
    int q, cur = 0;cin >> q;
    while(q --)
    {
        int x, y, t; cin >> x >> y >> t;
        while(a[cur] <= t && cur < n) 
        {
            floyd(cur);
            cur ++;
        }
        if(a[x] > t || a[y] > t || d[x][y] == INF)  cout << -1 << endl;
        else    cout << d[x][y] << endl;
    }
    return 0;
}
posted @ 2022-11-02 22:25  cxy8  阅读(11)  评论(0编辑  收藏  举报