Algorithm question brushing record (DAY5)

Posted by tharagleb on Sat, 26 Feb 2022 13:45:30 +0100

Who's in the Middle(poj2388)

Original question link
Method 1:
Wrong solution: use set, but ignore that there are no duplicate elements in set!!!
The error code is as follows:

#include<iostream>
#include<set>
using namespace std;
#define NMAX 10004
set<int> cow;
int N;
int main() {
	cin >> N;
	for (int i = 0;i < N;i++) {
		int cur;
		cin >> cur;
		cow.insert(cur);
	}
	
	//Note that the elements in the set cannot be accessed as elements of the array.
	set<int>::iterator it = cow.begin();
	for (int i = 0;it != cow.end();it++,i++) {
		if (i == N / 2) {
			cout << *it;
			return 0;
		}
	}
}

tips:
1.set can only be traversed through iterators
2. There are no duplicate elements in set

Method 2: sort sort

#include<iostream>
#include<algorithm>
using namespace std;
#define NMAX 10004
int cow[NMAX];
int N;
int main() {
	cin >> N;
	for (int i = 0;i < N;i++) {
		cin >> cow[i];
	}
	sort(cow, cow+N);
	cout << cow[N / 2];
	//Note that the elements in the set cannot be accessed as elements of the array.
	
}

tips:
1. The header file of sort is algorithm
2.sort has only two parameters to identify the sorting range. Note that this is an interval closed on the left and open on the right.

Supplement: Seven common sorting methods
Bubble sorting: compare and move two adjacent numbers from left to right. After a round, the rightmost is the most value.
Selective sorting: after a round of traversal, get the position of the most value and exchange it to the position it should belong to.
Insert sort: insert the first unordered number of the array into the ordered sequence formed on the left of the array.
Hill sort: perform insertion sort by grouping, and then perform the whole insertion sort on the results.
Quick sort : divide the array into two parts based on the benchmark, half larger than the benchmark and half smaller than the benchmark, and then arrange each half faster.
Merge and sort: divide the sequence to be arranged into multiple ordered sequences, and then merge the two ordered sequences into one ordered sequence, so as to repeat.
Heap sorting: get the maximum value through large top heap or small top heap.

ROADS(poj1724)

Original question link
Question:
1. How to store? Because there may be different roads between the two cities
2. The idea is to start from the shortest path to see whether the conditions for the principal are met?
3. There is search in the topic classification. Do you want to search? How to analyze the algorithm complexity of deep search

To solve problem 1, we should not use two-dimensional array for storage, because this limits the existence of only one edge between two cities. Therefore, combined with the fact that this problem is a directed graph, we use the structure of chained forward stars for storage.

For question 2, the idea of starting from the shortest path may have some problems. After solving the shortest path each time, if it is compared with the principal, it can be solved after the conditions are not met.

For question 3, since there are up to 10000 edges in the question, I always feel that the deep search will timeout. But think about it carefully. The number of midpoint in this question is small, and with the constraint of price, it is very convenient to prune, and then prune in combination with the minimum path length that has been calculated at present. Deep search may be a solution.
Try to use deep search, will it cause timeout? How to analyze the corresponding complexity?

#include<iostream>
using namespace std;
#define NMAX 102
#define RMAX 10004
#define INF 0x3f3f3f3f
struct Roads {
	int d;
	int l, c;
	int next;
}Rd[RMAX];
int Cy[NMAX];
int V[NMAX];
int K, N, R;
int tot = 0;
int res = INF;
void DFS(int x, int length, int cost) {
	V[x] = 1;//The representative has visited
	if (cost > K || length> res) goto ret; //If the current total price is greater than the principal or the total length is greater than the updated one, prune it directly
	if (x == N) {
		if (length < res) res = length;
		goto ret;
	}

	for (int c = Cy[x];c != -1;c = Rd[c].next) {
		if(!V[Rd[c].d]) DFS(Rd[c].d, length + Rd[c].l, cost + Rd[c].c);
	}
	ret:
	V[x] = 0;
}
int main() {
	cin >> K >> N >> R;

	for (int i = 1;i <= N;i++) Cy[i] = -1, V[i] = 0;

	for (int i = 0;i < R;i++) {
		int S, D, L, T;
		cin >> S >> D >> L >> T;
		Rd[tot].d = D;
		Rd[tot].l = L;
		Rd[tot].c = T;
		Rd[tot].next = Cy[S];
		Cy[S] = tot;
		tot++;
	}
	
	DFS(1, 0, 0);
	/*for (int c = Cy[1];c != 0;c = Rd[c].next) {
		DFS(Rd[c].d, Rd[c].l, Rd[c].c);
	}*/
	if (res == INF) cout << "-1";
	else cout << res;
}

tip:
Under these two conditions, we must not forget to change the access flag of x back.

Other solutions:
spfa+A *
Heuristic search based on spfa. To change the first in first out queue of spfa into a sort queue, we first need to get the shortest distance from each point to the nth point as the second part of the cost equation.

Cost equation: f = g + h. 1) f: cost. 2) g: the cost actually consumed at present. 3) H: estimated cost (what I encounter at present is to get the estimated cost by preprocessing and reverse drawing)

I think this method is similar to deep search, but it adds heuristic factors and takes advantage of the priority queue, so that the results may arrive faster.

Sorting It All Out(poj1094)

Original question link
Topic type: topological sorting

Question:
How should this sentence in the title be understood? This sentence implies that the sorting should not be carried out only after all edges are stored, but every time an edge is read in, a topological sorting should be carried out to obtain the minimum number of edges that can produce the result.

where xxx is the number of relations processed at the time either a
sorted sequence is determined or an inconsistency is found, whichever
comes first, and yyy...y is the sorted, ascending sequence.

The fundamental reason for changing the code for a long time lies in the wrong understanding of the topic meaning and topological sorting.
This problem requires a strict incremental relationship, while topological sorting gives a partial order relationship, which is reflected in the fact that there can be multiple points with degree 0 at the same time. Therefore, on the one hand, topological sorting can judge whether there are rings. On the other hand, it is necessary to control the points with degree 0. If there are more than one, the sorting is unsuccessful.
A major focus of this topic is how to set the return value after a topological sorting. I have spared a long time on this point. First, for any sort, we need to judge whether there is a ring (i.e. contradiction), which is the worst case. Directly return 0, and the main program can directly output an error for the received 0; The best case is that there is a completely strict sorting relationship, and all are involved in the sorting, so it directly returns 1. The main program can directly output the sorting success after receiving 1; In other cases, the output is - 1, which represents innocence and reactive power, but when all edges have been taken into account, there is an error at this time, because it represents that there is no sorting.

#include<iostream>
#include<queue> 
#include<vector>
using namespace std;
int n, m;
int map[26][26];
int Du[26];
int Ex[26];
vector<int> res;
int topo() {
	res.clear();
	queue<int> Q;//Q can only have one at most at a time
	int du[26];
	int unsure = 0;
	memcpy(du, Du, sizeof(du));
	//Find the first element with a degree of 1
	for (int i = 0;i < n;i++) {
		if (!du[i] && Ex[i]) Q.push(i);
	}
	while (!Q.empty()) {
		if (Q.size() > 1) unsure = 1; //Not a partial order relationship!!!!!
		int p = Q.front();
		Q.pop();
		res.push_back(p);
		for (int i = 0;i < n;i++) {
			if (map[p][i] == 1 && Ex[i]) {
				du[i]--;
				if (du[i] == 0) Q.push(i);
			}
		}
	}
	//First, judge whether there is a ring
	for (int i = 0;i < n;i++) {
		//A ring appears
		if (du[i] && Ex[i]) return 0;
	}
	
	if (!unsure && res.size()==n) return 1; //There is strict complete ordering
	else return -1;

	
}
int main() {
	while (1) {
		cin >> n >> m;
		if (n == 0 && m == 0) break;

		//Initialize all to 0
		memset(map, 0, sizeof(map));
		memset(Du, 0, sizeof(Du));
		memset(Ex, 0, sizeof(Du));
		for (int i = 0;i < m;i++) {
			char a, b;
			getchar();
			a = getchar();
			getchar();
			b = getchar();
			Du[b - 'A']++;
			map[a - 'A'][b - 'A'] = 1;
			Ex[a - 'A'] = 1;
			Ex[b - 'A'] = 1;
			int state = topo();
			if (state == 1) {
				//Read the following content
				for (int j = i + 1;j < m;j++) {
					getchar();getchar();getchar();getchar();
				}

				cout << "Sorted sequence determined after " << i + 1 << " relations: ";
				for (int j = 0;j < res.size();j++) {
					cout << char('A' + res[j]);
				}
				cout << "." << endl;

				break;
			}
			else if (state == 0) {
				
				//Read the following content
				for (int j = i + 1;j < m;j++) {
					getchar();getchar();getchar();getchar();
				}

				cout << "Inconsistency found after " << i + 1 << " relations." << endl;
				break;
			}
			else if(i==m-1) cout << "Sorted sequence cannot be determined." << endl;
		}
	}
}

tip: when performing a topological sorting, only the points that have appeared in the edge given by the title are sorted, which is specifically reflected in the Ex array.

Summary

Understanding Viva is not only for the meaning of the topic, but also for the algorithm itself.

Topics: C++ Algorithm data structure