Ultraviolet A 10163 storage keepers (two DP requests)
Http://uva.onlinejudge.org/index.php? Option = com_onlinejudge & Itemid = 8 & page = show_problem & problem = 1104
Question:
There are n warehouses (up to 100), m administrators (up to 30), and each administrator has a capability value p (the next row has m numbers, indicates the capability of each administrator ).Each Warehouse can only be managed by one administratorBut each administrator can take care of K warehouses (but the security value assigned to this warehouse is only p/K, K = 0, 1 ,.. n. p/K is an integer). Every month, the company will give the Administrator a salary. the salary of the Administrator is the value of P and, minimize the total wage on the premise that the security value of each warehouse is the highest.
Outputs the maximum security value and the minimum cost.
Analysis:
I did not pay attention to this question when I started"Each Warehouse can only be managed by one administrator". This condition. However, even if this condition is not met, it can be proved that, under optimal conditions, there must be a solution under the supervision of only one administrator in each warehouse.The proof is as follows:
Assume that there is a solution with the highest security value and the smallest sum of wages, and the current solution has two people in a warehouse. the security value of this warehouse must be determined by the person who gives the warehouse a high security value, so another person can leave it alone, then this person will either have another warehouse (the security value of another warehouse may be higher, and a higher security value may be obtained), or we can fire him. (get a lower salary) So when each warehouse has only one person at most, the solution we get may be better. therefore, we only need to consider the situation where each warehouse can only be managed by one person at most.
In the first DP process, calculate the maximum security value.
So that DP [I] [J] = X indicates that the maximum security value that can be obtained when I personally manage J warehouses is X.
Status Transfer: DP [I] [J] = max (DP [I-1] [J], min (DP [I-1] [K], P [I]/(J-k) 0 <= k <j.
The former indicates that the I user does not care about any warehouses, and the latter indicates that the I user must at least manage the J-K warehouses (the range of J-K is [1, J]).
The final request is: Maximum security value: L = DP [m] [N.
In the second DP process, the minimum total cost is obtained when the maximum security value is = L.
If DP [I] [J] = X indicates that I am the first person to take care of J warehouses and the maximum security value = L, the minimum cost is X.
Status Transfer: DP [I] [J] = min (DP [I-1] [J], DP [I-1] [k] + P [I]). where 0 <= k <= J-1P [I]/k> = L.
The former indicates that I do not care about any warehouses, and the latter indicates that I care about J-K warehouses at least. (J-K belongs to [1, J])
The final request is: The minimum overhead is y = DP [m] [N.
The DP process is finished, but the most common mistake is not DP, but the initialization of the DP array. the source code below is given in two copies, the first of which is to initialize the DP array in a unified manner, but it is specially processed for special boundary situations. the second part is to initialize the DP array for classification, but there is no need to deal with the special cases of marking. the principle is actually a two-dimensional matrix:
AC code 1: Initialize the DP array and perform special operations
# Include <cstdio> # include <cstring> # include <algorithm> using namespace STD; # define INF 1e8const int maxn = 100 + 5; int n, m; int P [maxn]; int DP [maxn] [maxn]; int L, Y; bool solve () {// DP [I] [J] The maximum security value memset (DP, 0, sizeof (DP) of the J warehouses under my personal care before the table )); for (INT I = 1; I <= m; I ++) for (Int J = 1; j <= N; j ++) {DP [I] [J] = DP [I-1] [J]; if (I = 1) // I = 1, when there is only one person, DP [I] [J] = max (DP [I] [J], p [I]/J ); else // I> = 2 {for (int K = 0; k <j; k ++) // The Front I-1 manages K warehouses, j-k I-Person Management Repository {If (k = 0) DP [I] [J] = max (DP [I] [J], p [I]/J ); else DP [I] [J] = max (DP [I] [J], min (DP [I-1] [K], P [I]/(J-k) ;}} if (! DP [m] [N]) return false; L = DP [m] [N]; // DP [I] [J] before the table, I personally take care of the minimum cost of J warehouses for (INT I = 1; I <= m; I ++) for (Int J = 1; j <= N; j ++) DP [I] [J] = inf; For (INT I = 1; I <= m; I ++) for (Int J = 1; j <= N; j ++) {if (I = 1) // I = 1, only one person {If (P [I]/j> = L) DP [I] [J] = P [I];} else // I> = 2 {DP [I] [J] = min (DP [I] [J], DP [I-1] [J]); for (int K = 0; k <j; k ++) // pre-i-1 personal management K repositories if (k = 0) {If (P [I]/j> = L) DP [I] [J] = min (DP [I] [J], p [I]);} else {If (P [I]/(J-k)> = L) DP [I] [J] = min (DP [I] [J], DP [I-1] [k] + P [I]); }}y = DP [m] [N]; return true;} int main () {While (scanf ("% d", & N, & M) = 2 & N) {for (INT I = 1; I <= m; I ++) scanf ("% d", & P [I]); If (solve () printf ("% d \ n", l, y ); else printf ("0 0 \ n");} return 0 ;}
AC code 2: class initialization without borders.
# Include <cstdio> # include <cstring> # include <algorithm> using namespace STD; # define INF 1e8const int maxn = 100 + 5; int n, m; int P [maxn]; int DP [maxn] [maxn]; int L, Y; bool solve () {// DP [I] [J] before the table, I personally care about the maximum security value of J warehouses for (INT I = 0; I <= m; I ++) DP [I] [0] = inf; For (INT I = 1; I <= N; I ++) DP [0] [I] = 0; for (INT I = 1; I <= m; I ++) for (Int J = 1; j <= N; j ++) {DP [I] [J] = DP [I-1] [J]; for (int K = 0; k <j; k ++) // The Front I-1 manages K warehouses, the I-person manages J-K warehouses DP [I] [J] = max (DP [I] [J] ], Min (DP [I-1] [K], p [I]/(J-k);} If (! DP [m] [N]) return false; L = DP [m] [N]; // DP [I] [J] before the table, I personally take care of the minimum cost of J warehouses for (INT I = 0; I <= m; I ++) DP [I] [0] = 0; For (INT I = 1; I <= N; I ++) DP [0] [I] = inf; for (INT I = 1; I <= m; I ++) for (Int J = 1; j <= N; j ++) {DP [I] [J] = DP [I-1] [J]; for (int K = 0; k <j; k ++) // pre-i-1 personal management K repositories if (P [I]/(J-k)> = L) DP [I] [J] = min (DP [I] [J], DP [I-1] [k] + P [I]);} y = DP [m] [N]; return true;} int main () {While (scanf ("% d", & N, & M) = 2 & N) {for (INT I = 1; I <= m; I ++) scanf ("% d", & P [I]); if (solve () printf ("% d \ n", l, Y); else printf ("0 0 \ n") ;}return 0 ;}
Ultraviolet A 10163 storage keepers (two DP requests)