2021-02-21 Luogu P1119 Floyd algorithm variant-post-disaster reconstruction

Summary:

Application of Floyd's algorithm-an investigation of the essence of Floyd's algorithm


Problem Description:

There are a total of n villages from 0 to n-1, and each village needs a certain amount of time to be rebuilt, and it cannot be opened to traffic until the rebuilding is completed. Solve the shortest distance from point i to point j at a given time. The
original problem is connected to Luogu P1119. Post-disaster reconstruction


Analysis of Algorithms:

Tip: The data given in the question are all sorted, including the number of villages in ascending order of the time they need to be reconstructed, and the time in the question is also sorted in ascending order. This provides a good idea for the ladder.

The essence of Floyd algorithm is to use the idea of ​​dynamic programming,Find the shortest path between two points by transiting through other points, Because we know that there are multiple roads between two points, if changing a road can shorten the distance, update the shortest distance. And its most essential idea is to use other points for transit, so as to achieve the purpose of finding the shortest path.

So, how to make a transfer? Between two points, one point can be used as a transit point to update the shortest path, or multiple points can be used to update the shortest path.
Combined code:

for(k=1;k<=n;k++)

    for(i=1;i<=n;i++)

        for(j=1;j<=n;j++)

            if(e[i][j]>e[i][k]+e[k][j])

                 e[i][j]=e[i][k]+e[k][j];
//核心代码,仅仅只有5行

The basic idea of ​​this code is: at the beginning, only vertices 1 and 2 are allowed to transit, and then only vertices 1 and 2 are allowed to transit...Allow to transit through all vertices 1 to n, find between any two points The shortest distance. In one sentence, it is the shortest distance from vertex i to vertex j through the first k point.

(Understand this passage carefully, it reveals the essence of this algorithm and provides a good method for this problem)

So far we have known that the Floyd algorithm is a step that uses other points to transfer to find the shortest path.

And we look back at the meaning of the title:

All edges are given, and each available point is updated in chronological order (that is, the village is built). For each point in time, an inter-point query is performed to find the difference between any two points for all the villages currently under construction. Is n’t the shortest path

just the idea of ​​using the first k nodes to update the shortest path in the Floyd algorithm?


Code and detailed comments:

#include <iostream>
#include <stdio.h>
#include <queue>
#include <vector>
#pragma warning(disable:4996)
#define INF 1000000
using namespace std;

struct question {
    
    
	int s;
	int dest;
	int day;
	question(int _s, int _dest, int _day) :s(_s), dest(_dest), day(_day) {
    
    }
};


class Solution {
    
    
public:
	int n, m;
	vector<vector<int>> cost;
	vector<int> time;
	vector<question> ques;
	vector<bool> visit;
	inline void update(int k)
	{
    
    
		for (int i = 0; i < n; ++i)
		{
    
    
			for (int j = 0; j < n; ++j)
			{
    
    
				if (cost[i][j] > cost[i][k] + cost[k][j])
				{
    
    
					cost[i][j] = cost[i][k] + cost[k][j];
				}
			}
		}
	}
	void out()
	{
    
    
		for (int i = 0; i < n; ++i)
		{
    
    
			for (int j = 0; j < n; ++j)
				cout << cost[i][j] << " ";
			cout << endl;
		}
	}
	void Floyd()
	{
    
    
		cin >> n >> m;
		cost.resize(n , vector<int>(n,INF));
		time.resize(n, 0);
		visit.resize(n + 1, false);
		for (int i = 0; i < n; ++i)
		{
    
    
			cin>>time[i];
		}
		for (int i = 1; i <= m; ++i)
		{
    
    
			int u, v, w;
			cin >> u >> v >> w;
			cost[u][v] = w;
			cost[v][u] = w;
		}
		for (int i = 0; i < n; ++i)
			cost[i][i] = 0;
		int Q;
		cin >> Q;
		for (int i = 0; i < Q; ++i)
		{
    
    
			int u, v, day;
			cin >> u >> v >> day;
			ques.push_back(question(u, v,day));
		}
		int k = 0;//当前遍历到第几个村庄
		for (int t = 0; t < Q;++t)
		{
    
    
			while (k<n&&ques[t].day >= time[k])
			{
    
    
				visit[k] = true;
				update(k);
				/*out();
				cout << endl << endl;*/
				++k;
			}
			if (visit[ques[t].s]==false||visit[ques[t].dest]==false||cost[ques[t].s][ques[t].dest] == INF)
				cout << "-1" << endl;
			else
				cout << cost[ques[t].s][ques[t].dest] << endl;
		}
	}
};


int main() {
    
    
	//freopen("in.txt", "r", stdin);
	Solution s;
	s.Floyd();
	return 0;
}

Error-prone

The author made a mistake in this question, which is the update function in the above code. When writing for the first time in the above update functionif statement judgment conditionThe judgment on the starting point i and the middle j is added on the basis of. Although there is a clear requirement in the title that only two villages can be opened to traffic after the reconstruction is completed, the judgment of whether the two start villages and the end villages have completed the reconstruction should not be added here, but should be added to the final output.

The reason is as follows:
Although the two villages have not been rebuilt, the actual roads have not been affected. That is, if the two villages are built, the actual shortest distance is fixed, if the update functionif statementChange to

if (visit[i] && visit[j] &&cost[i][j] > cost[i][k] + cost[k][j])
{
	cost[i][j] = cost[i][k] + cost[k][j];
}

Then, after the village is built, the actual shortest path will change. For example, for input

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

Suppose that on the third day, village 2 should be used as a transit point to update the global route, and village 3 has not been repaired at this time. But if the distance between village 3 and village 2 is not updated at this time, it is 1 (cost[2][3]=cost[3][2]=1), then when the fourth day comes, the distance from village 1 to village 4 is 5 instead of 4, which leads to an error. as the picture shows:

Guess you like

Origin blog.csdn.net/sddxszl/article/details/113925832