Daje jest tablica liczb mająca
Dla
Dla
int main() { scanf("%d%d%d",&n,&k,&c); REP(i,n) { REP(j,k) scanf("%d",&a[i][j]); } if (k == 1) { REP(i,n) scores.push_back(a[i][0]); } else if (k == 2) { REP(i,n) REP(j,i) { scores.push_back(max(a[i][0], a[j][0]) + max(a[i][1], a[j][1])); } } sort(scores.begin(), scores.end(), greater<int>()); printf("%d\n", scores[c-1]); }
Pomysł jest taki, że będziemy konstruować podzbiory w kolejności ich kosztów.
Łatwo jest znaleźć podzbiór o największym koszcie (czyli dla
Mamy zatem wybrany najlepszy podzbiór
Do pierwszej części wrzucimy podzbiory niezawierające wiersza
Łatwo zobaczyć, że wszystkie części są rozłączne ze sobą, oraz że pokrywają
wszystkie podzbiory z wyjątkiem
Każda z tych części może być opisana dwoma ciągami wierszy: tymi, które muszą być w podzbiorze, i tymi, które nie mogą być w podzbiorze. W każdej części możemy wybrać podzbiór o największym koszcie, tak jak opisywaliśmy wcześniej (musimy tylko wziąć pod uwagę ograniczenia nakładane na wybór wierszy).
Tak więc dla
Algorytm więc będzie następujący: na kolejce priorytetowej trzymamy wszystkie części (posortowane po koszcie najlepszego podzbioru), na które aktualnie podzielona jest przestrzeń wszystkich podzbiorów (na początku inicjujemy kolejkę częścią zawierającą wszystkie podzbiory, czyli nie mającą żadnych ograniczeń na wybór wierszy).
Potem
Podczas całego algorytmu na kolejkę wrzucimy co najwyżej
struct part { int cost; vector<int> team, forced, banned; part(const vector<int>& forced, const vector<int>& banned) : forced(forced), banned(banned) { team = forced; vector<int> used(n); for (int i : forced) { used[i] = 2; } for (int i : banned) { used[i] = 1; } for (int i = forced.size(); i < k; ++i) { int idx = -1, best = 0; REP(j,n) if (used[j] != 1) { if (idx == -1 || a[j][i] > a[idx][i]) { best = a[j][i]; if (!used[j]) { idx = j; } } } team.push_back(idx); used[idx] = 2; } cost = 0; REP(i,k) { int c = 0; REP(j,k) c = max(c, a[team[j]][i]); cost += c; } } void split(); bool operator<(const part& other) const { return cost < other.cost; } }; priority_queue<part> que; void part::split() { for (int i = forced.size(); i < k; ++i) { banned.push_back(team[i]); if (banned.size() > n-k) break; que.push(part(forced, banned)); banned.pop_back(); forced.push_back(team[i]); } }; int main() { scanf("%d%d%d",&n,&k,&c); REP(i,n) { REP(j,k) scanf("%d",&a[i][j]); } que.push(part(0, {}, {})); int cost; REP(i,c) { part p = que.top(); cost = p.cost; que.pop(); p.split(); } printf("%d\n", cost); }