luogu_1690 (greedy copy)

Posted by mark_18 on Tue, 25 Jan 2022 21:53:19 +0100

This is a very good shortest path + deep search exercise

Question surface:

Copy heard from Lu Niu that there are many treasures buried in a god field called yz, so copy came to this God land divided into regions. Lu Niu told me that there are treasures here, which are placed in the PI (1 < = Pi < = n) area. Copy also knows the distance between each area. Now start from area 1, get all the treasures and leave in area n. I'm very lazy, so I have to come to you to find a suitable route for him, so that he can walk the shortest distance.

Note: there is a sentence in the title

Note that the distance i to j is not necessarily equal to the distance j to i.

That is to say, when reading in, we need to consider the edge processing

It can also be said that this is a two-way graph with unequal weights

After getting the question surface, you can analyze:

1. We need to know the distance from each point to the treasure point

2. There are many possibilities to complete the treasure points here. We need to traverse them one by one

So what is the algorithm that satisfies these two conditions at the same time:

1. floyd

2. Depth first search

First of all, we need to memorize floyd's board:

void floyd(int n) {
	for (int k = 1; k <= n; k++) { //First, enumerate the transit points k
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				if (dis[i][k] != 0 && dis[k][j] != 0) {
					dis[i][j] = Min(dis[i][j], dis[i][k] + dis[k][j]);
				}
			}
		}
	}
} 

Using the idea of dynamic programming, we find the shortest distance between each point

Then we'll do a deep search

Before that, we have to deal with parameters and read in problems

There is a sentence in the question:

Next, an N*N matrix. The number in row i+1 and column j represents the distance between regions I and j

Then we can read:

memset(dis, INF, sizeof(dis)); //Initialize infinity to facilitate dynamic programming
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			long long w;
			cin >> w;
			dis[i][j] = Min(dis[i][j], w); //Handle heavy edges 
		}
	}

If you don't understand, you can compare the read subscript with the title

Now we know that there are p treasure points, so we can save the points with an array of a

Then there is the parameter problem

In the process of deep search, we need to pass in three parameters

At the same time, we use ans to record the best answer

1. Current point

2. The remaining treasure points to traverse

3. Total distance traveled (used to optimize ans)

Then, in order to avoid repeated traversal, we mark with the flag array

We can get the following code

void dfs(int now, int m, long long sum) {
	if (m == 0) { //After traversing all treasure points
		ans = min(sum + dis[now][n], ans); //optimization
		return; //to flash back
	}
	for (int i = 1; i <= p; i++) { //Enumerate a total of p treasure points
		if (!flag[i]) { //If not accessed
			flag[i] = 1; //sign
			dfs(a[i], m - 1, sum + dis[now][a[i]]);
            //(when you reach the next treasure point, there are m-1 treasure points left. The total distance sum plus the distance from the current point to the treasure point)
			flag[i] = 0; //Backtracking retag not accessed
		}
	}
}

Finally, we can output the best answer ans

Complete code

#include <bits/stdc++.h> //luogu 1690 by zqy 
#define maxn 105
#define INF 0x3f3f3f3f
using namespace std;
long long dis[maxn][maxn], n;
long long a[maxn], ans = INF;
bool flag[15];
int p;

int Min(long long x, long long y) {return x < y ? x : y;}
void floyd(int n) {
	for (int k = 1; k <= n; k++) {
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				if (dis[i][k] != 0 && dis[k][j] != 0) {
					dis[i][j] = Min(dis[i][j], dis[i][k] + dis[k][j]);
				}
			}
		}
	}
} 
void dfs(int now, int m, long long sum) {
	if (m == 0) {
		ans = min(sum + dis[now][n], ans);
		return;
	}
	for (int i = 1; i <= p; i++) {
		if (!flag[i]) {
			flag[i] = 1;
			dfs(a[i], m - 1, sum + dis[now][a[i]]);
			flag[i] = 0;
		}
	}
}
int main() {
	cin >> n;
	memset(dis, INF, sizeof(dis));
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			long long w;
			cin >> w;
			dis[i][j] = Min(dis[i][j], w); //Handle heavy edges 
		}
	}
	cin >> p;
	for (int i = 1; i <= p; i++) {
		cin >> a[i];
	}
	floyd(n);
	dfs(1, p, 0);
	cout << ans << endl;
	return 0;
} 

Sprinkle flowers

Konjaku is very weak. Please be tolerant

Topics: C++ Algorithm