Ranking (as of 2013-06-13): 61 out of 396
Language: C++
The priority queue implementation (the functions prefixed with "pqueue" and their associated definitions, etc. that are surrounded by the below 'extern "C"' block) is based on the code from https://github.com/vy/libpqueue and is licensed under the Apache 2.0 license:
  Copyright 2010 Volkan Yazici
  Copyright 2006-2010 The Apache Software Foundation
/* UVa 658 - It's not a Bug, it's a Feature! To build using Visual Studio 2008: cl -EHsc -O2 not_a_bug.cpp */ #include <iostream> #include <string> #include <vector> #include <cstdlib> #ifdef __ELAPSED_TIME__ #include <ctime> #endif using namespace std; #ifdef __cplusplus extern "C" { #endif /** priority data type */ typedef int pqueue_pri_t; /** callback functions to get/set/compare the priority of an element */ typedef pqueue_pri_t (*pqueue_get_pri_f)(void *a); typedef void (*pqueue_set_pri_f)(void *a, pqueue_pri_t pri); typedef int (*pqueue_cmp_pri_f)(pqueue_pri_t next, pqueue_pri_t curr); /** callback functions to get/set the position of an element */ typedef size_t (*pqueue_get_pos_f)(void *a); typedef void (*pqueue_set_pos_f)(void *a, size_t pos); /** debug callback function to print a entry */ typedef void (*pqueue_print_entry_f)(FILE *out, void *a); /** the priority queue handle */ typedef struct pqueue_t { size_t size; size_t avail; size_t step; pqueue_cmp_pri_f cmppri; pqueue_get_pri_f getpri; pqueue_set_pri_f setpri; pqueue_get_pos_f getpos; pqueue_set_pos_f setpos; void **d; } pqueue_t; #define left(i) ((i) << 1) #define right(i) (((i) << 1) + 1) #define parent(i) ((i) >> 1) pqueue_t * pqueue_init(size_t n, pqueue_cmp_pri_f cmppri, pqueue_get_pri_f getpri, pqueue_set_pri_f setpri, pqueue_get_pos_f getpos, pqueue_set_pos_f setpos) { pqueue_t *q; if (!(q = (pqueue_t *)malloc(sizeof(pqueue_t)))) return NULL; /* Need to allocate n+1 elements since element 0 isn't used. */ if (!(q->d = (void **)(malloc((n + 1) * sizeof(void *))))) { free(q); return NULL; } q->size = 1; q->avail = q->step = (n+1); /* see comment above about n+1 */ q->cmppri = cmppri; q->setpri = setpri; q->getpri = getpri; q->getpos = getpos; q->setpos = setpos; return q; } void pqueue_free(pqueue_t *q) { free(q->d); free(q); } size_t pqueue_size(pqueue_t *q) { /* queue element 0 exists but doesn't count since it isn't used. */ return (q->size - 1); } static void bubble_up(pqueue_t *q, size_t i) { size_t parent_node; void *moving_node = q->d[i]; pqueue_pri_t moving_pri = q->getpri(moving_node); for (parent_node = parent(i); ((i > 1) && q->cmppri(q->getpri(q->d[parent_node]), moving_pri)); i = parent_node, parent_node = parent(i)) { q->d[i] = q->d[parent_node]; q->setpos(q->d[i], i); } q->d[i] = moving_node; q->setpos(moving_node, i); } static size_t maxchild(pqueue_t *q, size_t i) { size_t child_node = left(i); if (child_node >= q->size) return 0; if ((child_node+1) < q->size && q->cmppri(q->getpri(q->d[child_node]), q->getpri(q->d[child_node+1]))) child_node++; /* use right child instead of left */ return child_node; } static void percolate_down(pqueue_t *q, size_t i) { size_t child_node; void *moving_node = q->d[i]; pqueue_pri_t moving_pri = q->getpri(moving_node); while ((child_node = maxchild(q, i)) && q->cmppri(moving_pri, q->getpri(q->d[child_node]))) { q->d[i] = q->d[child_node]; q->setpos(q->d[i], i); i = child_node; } q->d[i] = moving_node; q->setpos(moving_node, i); } int pqueue_insert(pqueue_t *q, void *d) { void *tmp; size_t i; size_t newsize; if (!q) return 1; /* allocate more memory if necessary */ if (q->size >= q->avail) { newsize = q->size + q->step; if (!(tmp = realloc(q->d, sizeof(void *) * newsize))) return 1; q->d = (void **)tmp; q->avail = newsize; } /* insert item */ i = q->size++; q->d[i] = d; bubble_up(q, i); return 0; } void pqueue_change_priority(pqueue_t *q, pqueue_pri_t new_pri, void *d) { size_t posn; pqueue_pri_t old_pri = q->getpri(d); q->setpri(d, new_pri); posn = q->getpos(d); if (q->cmppri(old_pri, new_pri)) bubble_up(q, posn); else percolate_down(q, posn); } void * pqueue_pop(pqueue_t *q) { void *head; if (!q || q->size == 1) return NULL; head = q->d[1]; q->d[1] = q->d[--q->size]; percolate_down(q, 1); return head; } #ifdef __cplusplus } #endif struct sequence { int time_; // time that has been taken so far in seconds int bug_; // bit sets describing the bus size_t pqueue_pos_; // used internally by libpqueue sequence() : time_(-1), bug_(0), pqueue_pos_(-1) {} sequence(int time, int bug) : time_(time), bug_(bug), pqueue_pos_(-1) {} static int get_distance(void* vd); static void set_distance(void* vd, int d); static int compare_distance(int next, int current); static size_t get_position(void* vd); static void set_position(void *vd, size_t position); }; int sequence::get_distance(void* vd) { return reinterpret_cast<sequence*>(vd)->time_; } void sequence::set_distance(void* vd, int d) { reinterpret_cast<sequence*>(vd)->time_ = d; } int sequence::compare_distance(int next, int current) { return current < next; } size_t sequence::get_position(void* vd) { return reinterpret_cast<sequence*>(vd)->pqueue_pos_; } void sequence::set_position(void *vd, size_t position) { reinterpret_cast<sequence*>(vd)->pqueue_pos_ = position; } /* Starting with the state of "+++...+", apply Dijkstra's shortest path algorithm. For each state from the queue, see if any available patchs can be applied: For a bug of state '+', a patch of '0' or '+' For a bug of state '-', a patch of '0' or '-' */ struct patch { static int n_, mask_; int time_; // time in seconds it takes to apply the patch int before_present_; // bugs that have to be present before the patch can be applied int before_absent_; // bugs that have to be present before the patch can be applied int before_unaffected_; // bugs that doesn't matter whether it is present or not int after_present_; // bugs that are fixed by the patch int after_unaffected_;// bugs that are not affected by the patch static void set_mask(int n); patch() {} patch(int time, const string& before, const string& after); int apply(int bug) const; }; int patch::n_ = 0, patch::mask_ = 0; void patch::set_mask(int n) { n_ = n; mask_ = (1 << n) - 1; } patch::patch(int time, const string& before, const string& after) : time_(time), before_present_(0), before_absent_(0), before_unaffected_(0), after_present_(0), after_unaffected_(0) { for (int i = 0; i < n_; i++) { if (i) { before_present_ <<= 1; before_absent_ <<= 1; before_unaffected_ <<= 1; after_present_ <<= 1; after_unaffected_ <<= 1; } if (before[i] == '+') before_present_ |= 1; else if (before[i] == '-') before_absent_ |= 1; else before_unaffected_ |= 1; if (after[i] == '+') after_present_ |= 1; else if (after[i] == '0') after_unaffected_ |= 1; } } int patch::apply(int bug) const { // see if the patch can be applied to bug, and if so, return the applied result int b = (bug & before_present_) | (~bug & before_absent_) | before_unaffected_; if (b != mask_) return -1; return after_present_ | (bug & after_unaffected_); } int shortest_path(int n, int m, const vector<patch>& patches) { int nr_sequences = 1 << n; vector<sequence> sequences(nr_sequences); // sequences[i] is the sequence for the bug of i vector<bool> queued(nr_sequences, false); // queued[i] is true if bug of i has already been queued pqueue_t* queue = pqueue_init(nr_sequences, sequence::compare_distance, sequence::get_distance, sequence::set_distance, sequence::get_position, sequence::set_position); int start = patch::mask_; for (int i = 0; i < m; i++) { int bug = patches[i].apply(start); if (bug != -1) { sequences[bug] = sequence(patches[i].time_, bug); queued[bug] = true; pqueue_insert(queue, &sequences[bug]); } } int fixed_time = -1; while (pqueue_size(queue)) { sequence* s = reinterpret_cast<sequence*>(pqueue_pop(queue)); s->pqueue_pos_ = -1; if (!s->bug_) { fixed_time = s->time_; break; } for (int i = 0; i < m; i++) { int bug = patches[i].apply(s->bug_); if (bug != -1) { int time = s->time_ + patches[i].time_; if (queued[bug]) { if (sequences[bug].pqueue_pos_ != -1 && sequences[bug].time_ > time) pqueue_change_priority(queue, time, &sequences[bug]); } else { sequences[bug] = sequence(time, bug); queued[bug] = true; pqueue_insert(queue, &sequences[bug]); } } } } pqueue_free(queue); return fixed_time; } int main() { #ifdef __ELAPSED_TIME__ clock_t start; #endif for (int pn = 1; ; pn++) { int n, m; cin >> n >> m; #ifdef __ELAPSED_TIME__ if (pn == 1) start = clock(); #endif if (!n && !m) break; patch::set_mask(n); vector<patch> patches(m); for (int i = 0; i < m; i++) { int time; string before, after; cin >> time >> before >> after; patches[i] = patch(time, before, after); } // apply Dijkstra's shortest path algorithm int fixed_time = shortest_path(n, m, patches); cout << "Product " << pn << endl; if (fixed_time != -1) cout << "Fastest sequence takes " << fixed_time << " seconds.\n"; else cout << "Bugs cannot be fixed.\n"; cout << endl; } #ifdef __ELAPSED_TIME__ cerr << "elapsed time = " << static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n"; #endif return 0; }
No comments:
Post a Comment