Luogu P1113 chores (DP, topology sorting)

Keywords: C++ Algorithm Graph Theory

[Title Description]
John's farm has a lot of chores to complete before milking the cows. Each chore takes a certain amount of time to complete it. For example, they have to gather the cows, drive them into the barn, wash their breasts and do some other work. It is necessary to finish all the chores as soon as possible, because there is more time to squeeze out more milk. Of course, some chores can only be carried out when others are completed. For example, only when the cow is driven into the cowshed can it start to wash its breasts, and the cow can't be milked before washing its breasts. We call these work preparations for completing this work. At least one chore does not require preparation. The work that can be completed at the earliest is marked as chores 1 1 1. John has something to do n n A list of n chores, and this list is in a certain order k ( k > 1 ) k(k>1) The preparation of K (k > 1) is only possible in chores 1 1 1 to k − 1 k−1 k − 1.
Write a program from 1 1 1 to n n n read in the job description of each chore. Calculate the shortest time for all chores to be completed. Of course, unrelated chores can work at the same time, and you can assume that John's farm has enough workers to complete any number of tasks at the same time.

[input format]
The first 1 1 Line 1: an integer n n n. Number of chores that must be completed ( 3 ≤ n ≤ 10 , 000 ) (3 \le n \le 10,000) (3≤n≤10,000);
The first 2 2 2 to ( n + 1 ) (n+1) (n+1) line: shared n n n lines, each line has some use 1 1 1 space separated integer, representing:

  • Job serial number( 1 1 1 to n n n. Is ordered in the input file);
  • Time required to complete the work l e n ( 1 ≤ l e n ≤ 100 ) len(1 \le len \le 100) len(1≤len≤100);
  • Some preparatory work that must be completed, and the total amount shall not exceed 100 100 100, by a number 0 0 End of 0. Some chores do not need to be prepared, only describe a separate task 0 0 0, no extra spaces will appear in the whole input file.

[output format]
An integer representing the minimum time required to complete all chores.

[input example]

7
1 5 0
2 2 1 0
3 3 2 0
4 6 1 0
5 1 2 4 0
6 8 2 4 0
7 4 3 5 6 0

[output example]

23

[analysis]

① DP analysis
Because tasks can be concurrent, if a task has a precursor, the optimal solution is to start immediately after the end of its latest precursor, and the task k k The precursor node of k must be less than k k k. So when reading in, you can select the largest transfer from its precursor. The final answer can be updated at the same time.

② Topological sorting analysis
We set w [ i ] w[i] w[i] stands for the second i i Time required for i chores, t w [ i ] tw[i] tw[i] indicates the second i i The earliest completion time of i chores, p r e pre pre indicates the precursor node of the chore, then t w [ i ] = m a x { t w [ p r e ] } + w [ i ] tw[i]=max\left\{ tw[pre]\right\}+w[i] tw[i]=max{tw[pre]}+w[i], finally, the maximum of the earliest completion time of each chore is the earliest time to complete all chores r e s = m a x { t w [ i ] } res=max\left\{ tw[i]\right\} res=max{tw[i]}.

[DP code]

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 10010;
int last[N], res;//last[i] is the earliest completion time of chore I
int n;

int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		int t, pre, s = 0;
		cin >> i >> t;
		while (cin >> pre, pre) s = max(s, last[pre]);//Find the latest completed precursor
		last[i] = s + t;//Start chores as soon as the front drive is completed at the latest i
		res = max(res, last[i]);//The answer is the maximum of the earliest completion time of all chores
	}
	cout << res << endl;
	return 0;
}

[topology sorting code]

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

const int N = 10010, M = 1000010;
int e[M], ne[M], h[N], idx;
int w[N], in[N], tw[N], res;
int n;

void add(int u, int v)
{
	e[idx] = v, ne[idx] = h[u], h[u] = idx++;
}

void topSort()
{
	queue<int> Q;
	for (int i = 1; i <= n; i++)
		if (!in[i]) Q.push(i), tw[i] = w[i];//The earliest completion time of chores without precursor nodes is the time to complete itself
	while (Q.size())
	{
		auto t = Q.front();
		Q.pop();
		res = max(res, tw[t]);//The earliest completion time of the node in the queue must have been updated
		for (int i = h[t]; ~i; i = ne[i])
			if (!--in[e[i]]) Q.push(e[i]), tw[e[i]] = max(tw[e[i]], w[e[i]] + tw[t]);
			else tw[e[i]] = max(tw[e[i]], w[e[i]] + tw[t]);
	}
}

int main()
{
	cin >> n;
	memset(h, -1, sizeof h);
	for (int i = 1; i <= n; i++)
	{
		cin >> i >> w[i];
		int x;
		while (cin >> x, x) add(x, i), in[i]++;
	}
	topSort();
	cout << res << endl;
	return 0;
}

Posted by cjl on Wed, 17 Nov 2021 17:04:04 -0800