#include <iostream> #include <vector> #include <algorithm> #include <assert.h> using namespace std; struct zadanie { private: int pocz, kroki, zapas; // kroki - ile sekund zadanie ma sie wykonywac; zapas - ile sekund moze czekac public: zadanie(int p, int k, int c) :pocz(p+1), kroki(c), zapas(k-p-c) {} // p+1 - bo zadanie mozna zaczac po 'p' sek., a wiec najwczesniej w 'p+1'-szej sek. static int t; // aktualna chwila czasu int jaki_zapas() const { return zapas; } bool czy_aktywne() const { assert(zapas >=0); return (t>=pocz && kroki>0); } bool czy_skonczone() const { return kroki==0; } bool wykonaj() // zwraca, czy zadanie zostalo wykonane { if (czy_aktywne()) { kroki--; return true; // zadanie bylo wykonywne w chwili t } else return false; // zadanie nieaktywne - nie mozna go wykonac } bool wstrzymaj() // zwraca, czy zadanie nie przekroczylo limitu czasu na skutek wstrzymania { if (czy_aktywne()) { if (zapas==0) return false; // zadanie nie skonczone na czas!!!! else { zapas--; return true; // zadanie moze poczekac } } else return true; // zadanie nieaktywne - czekanie mu nie szkodzi } static bool comp_zad(const zadanie& x, const zadanie& y) // zadanie aktywne jest pilniejsze // w przypadku rownosci - zadanie z mniejszym zapasem jest pilniejsze { if (x.czy_aktywne() != y.czy_aktywne()) return x.czy_aktywne() > y.czy_aktywne(); else if (x.czy_aktywne()) // oba zadania aktywne return x.zapas < y.zapas; else return false; // zadan nieaktywnych nie warto sortowac } static bool comp_zad_zapas(const zadanie& x, const zadanie& y) { return x.zapas < y.zapas; } static bool comp_zad_pocz(const zadanie& x, const zadanie& y) { // malejaco po czasie rozpoczecia return x.pocz > y.pocz; } }; int zadanie::t; bool dodaj_zadania(vector<zadanie>& kolejka, vector<zadanie>& aktywne) // przenoi zadania, dla ktorych pocz>=t, z listy oczekujacych do aktywnych // zwraca czy jakies zadania zostaly dodane { if (kolejka.empty()==false && (kolejka.back()).czy_aktywne()) { while (kolejka.empty()==false && kolejka.back().czy_aktywne()) { aktywne.push_back(kolejka.back()); kolejka.pop_back(); } return true; } else return false; } void napraw_kolejnosc(vector<zadanie>& aktywne, vector<zadanie>::iterator podzial) { // podzial wskazuje na pierwsze niewykonane zadanie if (podzial->jaki_zapas() < (podzial-1)->jaki_zapas()) { auto start = lower_bound(aktywne.begin(), podzial, (podzial-1)->jaki_zapas(), [](const zadanie& x, const int w){return x.jaki_zapas() < w;}); auto stop = lower_bound(podzial, aktywne.end(), 1+podzial->jaki_zapas(), [](const zadanie& x, const int w){return x.jaki_zapas() < w;}); reverse(start, stop); } } int main() { int ile_zadan, limit; // limit = liczba procesorow cin>> ile_zadan >>limit; if (ile_zadan <=limit) // wszystkie zadania da sie wykonac jednoczesnie { cout<<"TAK"<<endl; return 0; } // wczytaj liste zadan vector<zadanie> lista_zadan; lista_zadan.reserve(ile_zadan); int t_start = 1000*1000, t_stop=0; for (int ii=0; ii<ile_zadan; ii++) { int p, k, c; cin>> p>>k >>c; lista_zadan.push_back(zadanie(p,k,c)); // zakres czasu, w ktorym istnieja aktywne zadania t_start = min(t_start, p+1); t_stop = max(t_stop, k); } // sortowanie listy zadan MALEJACO po czasie rozpoczenia - utworzenie stosu zadan sort(lista_zadan.begin(), lista_zadan.end(), zadanie::comp_zad_pocz); // lista aktywnych zadan vector<zadanie> lista_aktywnych; lista_aktywnych.reserve(ile_zadan); // wykonywnie zadan krokowo w kazdej sekundzie int ile_skonczonych = 0; for (zadanie::t = t_start; zadanie::t <= t_stop && ile_skonczonych <ile_zadan; zadanie::t++) { // dodaj aktywne zadania i posortuj je rosnaco po zapasie czasu if (dodaj_zadania(lista_zadan, lista_aktywnych)) { sort(lista_aktywnych.begin(), lista_aktywnych.end(), zadanie::comp_zad_zapas); } // wykonaj tyle najpilniejszych zadan na ile pozwala limit auto iter = lista_aktywnych.begin(); int licznik = 0; // licznik zadan wykonywanych jednoczesnie w tej chwili czasu for (; iter!= lista_aktywnych.end() && licznik<limit; ++iter, licznik++) { iter->wykonaj(); } // pozostale aktywne zadania zostaja wstrzymane auto podzial = iter; for (; iter!= lista_aktywnych.end(); ++iter) { bool czy_ok = iter->wstrzymaj(); if (czy_ok == false) // zadanie nie skonczone na czas { cout<<"NIE"<<endl; return 0; } } // naprawienie kolejnosci aktywnych zadan if (podzial != lista_aktywnych.end()) { napraw_kolejnosc(lista_aktywnych, podzial); } // policzenie i usuniecie z listy skonczonych zadan auto nowy_end = remove_if(lista_aktywnych.begin(), lista_aktywnych.end(), [](const zadanie& x){return x.czy_skonczone();}); if (nowy_end != lista_aktywnych.end()) { ile_skonczonych += (lista_aktywnych.end() - nowy_end); lista_aktywnych.erase(nowy_end, lista_aktywnych.end()); } } assert(ile_skonczonych == ile_zadan); // pomyslnie wykonano wszyskie zadania cout<<"TAK"<<endl; return 0; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | #include <iostream> #include <vector> #include <algorithm> #include <assert.h> using namespace std; struct zadanie { private: int pocz, kroki, zapas; // kroki - ile sekund zadanie ma sie wykonywac; zapas - ile sekund moze czekac public: zadanie(int p, int k, int c) :pocz(p+1), kroki(c), zapas(k-p-c) {} // p+1 - bo zadanie mozna zaczac po 'p' sek., a wiec najwczesniej w 'p+1'-szej sek. static int t; // aktualna chwila czasu int jaki_zapas() const { return zapas; } bool czy_aktywne() const { assert(zapas >=0); return (t>=pocz && kroki>0); } bool czy_skonczone() const { return kroki==0; } bool wykonaj() // zwraca, czy zadanie zostalo wykonane { if (czy_aktywne()) { kroki--; return true; // zadanie bylo wykonywne w chwili t } else return false; // zadanie nieaktywne - nie mozna go wykonac } bool wstrzymaj() // zwraca, czy zadanie nie przekroczylo limitu czasu na skutek wstrzymania { if (czy_aktywne()) { if (zapas==0) return false; // zadanie nie skonczone na czas!!!! else { zapas--; return true; // zadanie moze poczekac } } else return true; // zadanie nieaktywne - czekanie mu nie szkodzi } static bool comp_zad(const zadanie& x, const zadanie& y) // zadanie aktywne jest pilniejsze // w przypadku rownosci - zadanie z mniejszym zapasem jest pilniejsze { if (x.czy_aktywne() != y.czy_aktywne()) return x.czy_aktywne() > y.czy_aktywne(); else if (x.czy_aktywne()) // oba zadania aktywne return x.zapas < y.zapas; else return false; // zadan nieaktywnych nie warto sortowac } static bool comp_zad_zapas(const zadanie& x, const zadanie& y) { return x.zapas < y.zapas; } static bool comp_zad_pocz(const zadanie& x, const zadanie& y) { // malejaco po czasie rozpoczecia return x.pocz > y.pocz; } }; int zadanie::t; bool dodaj_zadania(vector<zadanie>& kolejka, vector<zadanie>& aktywne) // przenoi zadania, dla ktorych pocz>=t, z listy oczekujacych do aktywnych // zwraca czy jakies zadania zostaly dodane { if (kolejka.empty()==false && (kolejka.back()).czy_aktywne()) { while (kolejka.empty()==false && kolejka.back().czy_aktywne()) { aktywne.push_back(kolejka.back()); kolejka.pop_back(); } return true; } else return false; } void napraw_kolejnosc(vector<zadanie>& aktywne, vector<zadanie>::iterator podzial) { // podzial wskazuje na pierwsze niewykonane zadanie if (podzial->jaki_zapas() < (podzial-1)->jaki_zapas()) { auto start = lower_bound(aktywne.begin(), podzial, (podzial-1)->jaki_zapas(), [](const zadanie& x, const int w){return x.jaki_zapas() < w;}); auto stop = lower_bound(podzial, aktywne.end(), 1+podzial->jaki_zapas(), [](const zadanie& x, const int w){return x.jaki_zapas() < w;}); reverse(start, stop); } } int main() { int ile_zadan, limit; // limit = liczba procesorow cin>> ile_zadan >>limit; if (ile_zadan <=limit) // wszystkie zadania da sie wykonac jednoczesnie { cout<<"TAK"<<endl; return 0; } // wczytaj liste zadan vector<zadanie> lista_zadan; lista_zadan.reserve(ile_zadan); int t_start = 1000*1000, t_stop=0; for (int ii=0; ii<ile_zadan; ii++) { int p, k, c; cin>> p>>k >>c; lista_zadan.push_back(zadanie(p,k,c)); // zakres czasu, w ktorym istnieja aktywne zadania t_start = min(t_start, p+1); t_stop = max(t_stop, k); } // sortowanie listy zadan MALEJACO po czasie rozpoczenia - utworzenie stosu zadan sort(lista_zadan.begin(), lista_zadan.end(), zadanie::comp_zad_pocz); // lista aktywnych zadan vector<zadanie> lista_aktywnych; lista_aktywnych.reserve(ile_zadan); // wykonywnie zadan krokowo w kazdej sekundzie int ile_skonczonych = 0; for (zadanie::t = t_start; zadanie::t <= t_stop && ile_skonczonych <ile_zadan; zadanie::t++) { // dodaj aktywne zadania i posortuj je rosnaco po zapasie czasu if (dodaj_zadania(lista_zadan, lista_aktywnych)) { sort(lista_aktywnych.begin(), lista_aktywnych.end(), zadanie::comp_zad_zapas); } // wykonaj tyle najpilniejszych zadan na ile pozwala limit auto iter = lista_aktywnych.begin(); int licznik = 0; // licznik zadan wykonywanych jednoczesnie w tej chwili czasu for (; iter!= lista_aktywnych.end() && licznik<limit; ++iter, licznik++) { iter->wykonaj(); } // pozostale aktywne zadania zostaja wstrzymane auto podzial = iter; for (; iter!= lista_aktywnych.end(); ++iter) { bool czy_ok = iter->wstrzymaj(); if (czy_ok == false) // zadanie nie skonczone na czas { cout<<"NIE"<<endl; return 0; } } // naprawienie kolejnosci aktywnych zadan if (podzial != lista_aktywnych.end()) { napraw_kolejnosc(lista_aktywnych, podzial); } // policzenie i usuniecie z listy skonczonych zadan auto nowy_end = remove_if(lista_aktywnych.begin(), lista_aktywnych.end(), [](const zadanie& x){return x.czy_skonczone();}); if (nowy_end != lista_aktywnych.end()) { ile_skonczonych += (lista_aktywnych.end() - nowy_end); lista_aktywnych.erase(nowy_end, lista_aktywnych.end()); } } assert(ile_skonczonych == ile_zadan); // pomyslnie wykonano wszyskie zadania cout<<"TAK"<<endl; return 0; } |