#include<stdio.h> #include<stdlib.h> #include<stdint.h> using namespace std; int n,m; uint32_t itemSum=0; // suma wag wszystkich elementow uint32_t packSum=0; // suma miesjca plecakow struct Item { int weight; ///< Rozmiar przedmiotu int pack; ///< w którym plecaku jest }; struct Pack { int size; /// rozmiar plecaka int left; /// pozostałe wolne miejsce int items; /// ilość elementów w plecaku int item[24]; /// elementy plecaka }; Item items[24]; Pack packs[100]; /** Dodaje przedmiot do plecaka */ bool add(int pack, int item) { Pack& p=packs[pack]; Item& i=items[item]; if(p.left>=i.weight) { p.left-=i.weight; i.pack=pack; p.item[p.items++]=item; return true; } else return false; } /** Usuwa wszystkie przedmioty z plecaka */ void removeAll(int pack) { Pack& p=packs[pack]; for(int i=0;i<p.items;++i) { items[p.item[i]].pack=-1; // oznaczamy jako nieprzypisany } p.items=0; p.left=p.size; } int itemCmp(const void* e1, const void* e2) { return ((Item*)e2)->weight - ((Item*)e1)->weight; } int packCmp(const void* e1, const void* e2) { return ((Pack*)e2)->size - ((Pack*)e1)->size; } uint32_t tsts=0; bool packBackpack(int mi, uint32_t itemSize, uint32_t packSize, int startIndex) { if(++tsts>=60000000) return false; // ucieczka od trudnego zagadnienia if(itemSize==0) return true; // wszystko spakowane if(mi==-1) return false; // koniec plecaków, a coś jeszcze zostało if(itemSize>packSize) return false; // nie ma już szansy - za mało pozostałego miejsca Pack& p=packs[mi]; for(int i=startIndex;i<n;++i) { if(items[i].pack!=-1) continue; // już użyty int w=items[i].weight; if(p.left>=w) { // wrzucamy i testujemy rekurencyjnie items[i].pack=mi; p.left-=w; if(packBackpack(mi,itemSize-w,packSize-w,i+1)) return true; // znaleziono ułożenie items[i].pack=-1; p.left+=w; } } if(startIndex==0) return false; // plecak nie może być pusty return packBackpack(mi-1,itemSize,packSize-p.left,0); } /** Metoda szukająca miejsca dla element ii-tego */ bool packItems() { uint32_t packSum=0; for(int i=0;i<n;++i) items[i].pack=-1; for(int i=0;i<m;++i) { packs[i].left=packs[i].size; packSum+=packs[i].size; } if(packBackpack(m-1, itemSum, packSum, 0)) { for(int i=0;i<m;++i) { packs[i].left=packs[i].size; packs[i].items=0; } for(int i=0;i<n;++i) add(items[i].pack,i); return true; } else return false; } int main() { scanf("%d %d",&n,&m); for(int i=0;i<n;++i) { scanf("%d",&items[i].weight); items[i].pack=-1; itemSum+=items[i].weight; } for(int i=0;i<m;++i) { scanf("%d",&packs[i].size); packs[i].left=packs[i].size; packs[i].items=0; } qsort(items, n, sizeof(Item), itemCmp); qsort(packs, m, sizeof(Pack), packCmp); // plecaków nie może być więcej niż rzeczy if(m>n) m=n; { // sprawdzamy czy jest plecak na najwięszką rzecz bool minSize=false; for(int i=0;i<m;++i) { packSum+=packs[i].size; // przy okazji obliczamy sumę przestrzeni if(packs[i].size>=items[0].weight) minSize=true; } if(!minSize) { // nie ma plecaka dla największego elementu printf("NIE\n"); return 0; } if(packSum<itemSum) { // wszystkich plecaków bedzie za mało, więc nie ma szansy printf("NIE\n"); return 0; } } { // usuwamy plecaki, które nie pomieszczą żadnej rzeczy while((m>0)&&(packs[m-1].size<items[n-1].weight)) { #ifdef DEBUG printf("Removing to small backpack: %d\n",packs[m-1].size); #endif --m; } if(m==0) { printf("NIE\n"); return 0; } } #ifdef DEBUG printf("Items #%d: ",n); for(int i=0;i<n;++i) printf("%d ",items[i].weight); printf(" += %u\n",itemSum); printf("Packs #%d: ",m); for(int i=0;i<m;++i) printf("%d ",packs[i].size); printf(" += %u\n",packSum); #endif // wrzucmy elementy do plecaków metodą na siłe { int processed=0; int p=0; for(int i=0;i<n;++i) { for(int j=0;j<m;++j) { if(add(j,i)) { ++processed; break; } } } } #ifdef DEBUG printf("Items #%d: ",n); for(int i=0;i<n;++i) printf("%d@%d ",items[i].weight,items[i].pack); printf("\n"); #endif // jeżeli po pierwszym podejściu zostały jakieś wolne plecaki, to się ich pozbywamy while((m>0)&&(packs[m-1].items==0)) { #ifdef DEBUG printf("Removing unused backpack: %d\n",packs[m-1].size); #endif packSum-=packs[m-1].size; --m; } // pakujemy rzeczy dopóki jest to możliwe int best=-1; for(;;) { bool valid=true; // jeżeli jest coś poza plecakami, to chcemy to zapakować // najpierw sprawdzamy, czy jest to mozliwe { uint32_t left=0; // suma wolnego miejsca w plecakach uint32_t sum=0; // suma elementow do zapakowania for(int i=0;i<m;++i) left+=packs[i].left; for(int i=0;i<n;++i) if(items[i].pack==-1) sum+=items[i].weight; if(left<sum) { #ifdef DEBUG printf("Cannot decrease backpacks - left space (%u) < items to packs (%u)\n",left,sum); #endif break; // nie ma miejsca na elementy do dodania } } #if 0 for(int i=0;i<n;++i) { if(items[i].pack==-1) { // nie jest nigdzie wpakowany, trzeba znaleźć miejsce dla tego elementu #ifdef DEBUG printf("Trying to pack item %d\n",items[i].weight); #endif if(!packItem(i)) { // nie udało się znaleźć miejsca, to koniec #ifdef DEBUG printf("Cannot back pitem %d\n",items[i].weight); #endif valid=false; break; } } } #else valid=packItems(); #endif if(!valid) break; // nie można upchnąć rzeczy, przy takiej konfiguracji best=m; if(m==1) break; // nie ma więcej plecaków, to nie ma za bardzo sensu // próbujemy usunąć najmniejszy plecak --m; removeAll(m); #ifdef DEBUG printf("All items packed, trying to decrease backpacks\n"); printf("Items #%d: ",n); for(int i=0;i<n;++i) printf("%d@%d ",items[i].weight,items[i].pack); printf("\n"); #endif } if(best==-1) printf("NIE\n"); else printf("%d\n",best); 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 213 214 215 216 217 218 219 220 221 222 223 224 | #include<stdio.h> #include<stdlib.h> #include<stdint.h> using namespace std; int n,m; uint32_t itemSum=0; // suma wag wszystkich elementow uint32_t packSum=0; // suma miesjca plecakow struct Item { int weight; ///< Rozmiar przedmiotu int pack; ///< w którym plecaku jest }; struct Pack { int size; /// rozmiar plecaka int left; /// pozostałe wolne miejsce int items; /// ilość elementów w plecaku int item[24]; /// elementy plecaka }; Item items[24]; Pack packs[100]; /** Dodaje przedmiot do plecaka */ bool add(int pack, int item) { Pack& p=packs[pack]; Item& i=items[item]; if(p.left>=i.weight) { p.left-=i.weight; i.pack=pack; p.item[p.items++]=item; return true; } else return false; } /** Usuwa wszystkie przedmioty z plecaka */ void removeAll(int pack) { Pack& p=packs[pack]; for(int i=0;i<p.items;++i) { items[p.item[i]].pack=-1; // oznaczamy jako nieprzypisany } p.items=0; p.left=p.size; } int itemCmp(const void* e1, const void* e2) { return ((Item*)e2)->weight - ((Item*)e1)->weight; } int packCmp(const void* e1, const void* e2) { return ((Pack*)e2)->size - ((Pack*)e1)->size; } uint32_t tsts=0; bool packBackpack(int mi, uint32_t itemSize, uint32_t packSize, int startIndex) { if(++tsts>=60000000) return false; // ucieczka od trudnego zagadnienia if(itemSize==0) return true; // wszystko spakowane if(mi==-1) return false; // koniec plecaków, a coś jeszcze zostało if(itemSize>packSize) return false; // nie ma już szansy - za mało pozostałego miejsca Pack& p=packs[mi]; for(int i=startIndex;i<n;++i) { if(items[i].pack!=-1) continue; // już użyty int w=items[i].weight; if(p.left>=w) { // wrzucamy i testujemy rekurencyjnie items[i].pack=mi; p.left-=w; if(packBackpack(mi,itemSize-w,packSize-w,i+1)) return true; // znaleziono ułożenie items[i].pack=-1; p.left+=w; } } if(startIndex==0) return false; // plecak nie może być pusty return packBackpack(mi-1,itemSize,packSize-p.left,0); } /** Metoda szukająca miejsca dla element ii-tego */ bool packItems() { uint32_t packSum=0; for(int i=0;i<n;++i) items[i].pack=-1; for(int i=0;i<m;++i) { packs[i].left=packs[i].size; packSum+=packs[i].size; } if(packBackpack(m-1, itemSum, packSum, 0)) { for(int i=0;i<m;++i) { packs[i].left=packs[i].size; packs[i].items=0; } for(int i=0;i<n;++i) add(items[i].pack,i); return true; } else return false; } int main() { scanf("%d %d",&n,&m); for(int i=0;i<n;++i) { scanf("%d",&items[i].weight); items[i].pack=-1; itemSum+=items[i].weight; } for(int i=0;i<m;++i) { scanf("%d",&packs[i].size); packs[i].left=packs[i].size; packs[i].items=0; } qsort(items, n, sizeof(Item), itemCmp); qsort(packs, m, sizeof(Pack), packCmp); // plecaków nie może być więcej niż rzeczy if(m>n) m=n; { // sprawdzamy czy jest plecak na najwięszką rzecz bool minSize=false; for(int i=0;i<m;++i) { packSum+=packs[i].size; // przy okazji obliczamy sumę przestrzeni if(packs[i].size>=items[0].weight) minSize=true; } if(!minSize) { // nie ma plecaka dla największego elementu printf("NIE\n"); return 0; } if(packSum<itemSum) { // wszystkich plecaków bedzie za mało, więc nie ma szansy printf("NIE\n"); return 0; } } { // usuwamy plecaki, które nie pomieszczą żadnej rzeczy while((m>0)&&(packs[m-1].size<items[n-1].weight)) { #ifdef DEBUG printf("Removing to small backpack: %d\n",packs[m-1].size); #endif --m; } if(m==0) { printf("NIE\n"); return 0; } } #ifdef DEBUG printf("Items #%d: ",n); for(int i=0;i<n;++i) printf("%d ",items[i].weight); printf(" += %u\n",itemSum); printf("Packs #%d: ",m); for(int i=0;i<m;++i) printf("%d ",packs[i].size); printf(" += %u\n",packSum); #endif // wrzucmy elementy do plecaków metodą na siłe { int processed=0; int p=0; for(int i=0;i<n;++i) { for(int j=0;j<m;++j) { if(add(j,i)) { ++processed; break; } } } } #ifdef DEBUG printf("Items #%d: ",n); for(int i=0;i<n;++i) printf("%d@%d ",items[i].weight,items[i].pack); printf("\n"); #endif // jeżeli po pierwszym podejściu zostały jakieś wolne plecaki, to się ich pozbywamy while((m>0)&&(packs[m-1].items==0)) { #ifdef DEBUG printf("Removing unused backpack: %d\n",packs[m-1].size); #endif packSum-=packs[m-1].size; --m; } // pakujemy rzeczy dopóki jest to możliwe int best=-1; for(;;) { bool valid=true; // jeżeli jest coś poza plecakami, to chcemy to zapakować // najpierw sprawdzamy, czy jest to mozliwe { uint32_t left=0; // suma wolnego miejsca w plecakach uint32_t sum=0; // suma elementow do zapakowania for(int i=0;i<m;++i) left+=packs[i].left; for(int i=0;i<n;++i) if(items[i].pack==-1) sum+=items[i].weight; if(left<sum) { #ifdef DEBUG printf("Cannot decrease backpacks - left space (%u) < items to packs (%u)\n",left,sum); #endif break; // nie ma miejsca na elementy do dodania } } #if 0 for(int i=0;i<n;++i) { if(items[i].pack==-1) { // nie jest nigdzie wpakowany, trzeba znaleźć miejsce dla tego elementu #ifdef DEBUG printf("Trying to pack item %d\n",items[i].weight); #endif if(!packItem(i)) { // nie udało się znaleźć miejsca, to koniec #ifdef DEBUG printf("Cannot back pitem %d\n",items[i].weight); #endif valid=false; break; } } } #else valid=packItems(); #endif if(!valid) break; // nie można upchnąć rzeczy, przy takiej konfiguracji best=m; if(m==1) break; // nie ma więcej plecaków, to nie ma za bardzo sensu // próbujemy usunąć najmniejszy plecak --m; removeAll(m); #ifdef DEBUG printf("All items packed, trying to decrease backpacks\n"); printf("Items #%d: ",n); for(int i=0;i<n;++i) printf("%d@%d ",items[i].weight,items[i].pack); printf("\n"); #endif } if(best==-1) printf("NIE\n"); else printf("%d\n",best); return 0; } |