#include #include #include #include #include #include #define NONE -1 enum { SORT_DESC = 0, SORT_ASC }; enum { UNSORTED = 0, SORT_WR, SORT_VR, SORT_RW, SORT_RV}; static int debug; static int sort; static int sort_order; typedef struct _InputItem { int i; /* item index */ int v; /* item value */ int w; /* item weight */ } InputItem; typedef struct _SolverItem { int i; /* index of the selected item */ int v; /* cumulated value */ int w; /* cumulated weight */ } SolverItem; typedef struct _Solver { int k; /* capacity */ int n; /* items # */ int w_sum; /* sum of input items weight */ InputItem *items; /* items */ SolverItem *column; /* solver column */ } Solver; static int item_cmp(const void *p1, const void *p2) { int ret; float r1, r2; const InputItem *i1, *i2; i1 = (const InputItem *) p1; i2 = (const InputItem *) p2; ret = ((sort_order == SORT_ASC) ? 1 : -1); if (sort == SORT_WR) { if (i1->w > i2->w) return ret; if (i1->w < i2->w) return -ret; } else if (sort == SORT_VR) { if (i1->v > i2->v) return ret; if (i1->v < i2->v) return -ret; } else // SORT_RW | SORT_RV { r1 = i1->v / (float)i1->w; r2 = i2->v / (float)i2->w; if (r1 > r2) return ret; if (r1 < r2) return -ret; } if (sort == SORT_RW) { if (i1->w > i2->w) return ret; if (i1->w < i2->w) return -ret; } else if (sort == SORT_RV) { if (i1->v > i2->v) return ret; if (i1->v < i2->v) return -ret; } else // SORT_WR | SORT_VR { r1 = i1->v / (float)i1->w; r2 = i2->v / (float)i2->w; if (r1 > r2) return ret; if (r1 < r2) return -ret; } return 0; } static void solve(Solver* solver) { int n, k; int v, w; int i, j; int min_c, lower_bound; const InputItem *item; SolverItem *data; const SolverItem *up_left; unsigned int counter; n = solver->n; k = solver->k; min_c = solver->w_sum; if (debug > 2) { printf("\nformat V(i,W)\n"); } /* SOLVE */ counter = 0; item = solver->items; for (i = 0; i < n; i++, item++) { v = item->v; w = item->w; data = solver->column + solver->k; up_left = solver->column + (solver->k - w); // this computes the top-left bottom-right diagonal, // values above this don't need to be computed min_c -= w; lower_bound = (k - min_c); if (lower_bound < w) lower_bound = w; for (j = k; j >= lower_bound; j--, data--, up_left--) { counter++; if (data->v < (v + up_left->v)) { data->i = i; data->v = v + up_left->v; data->w = w + up_left->w; } } if (debug > 2) { printf("i=%d; j=k; j<=%d:\n", i, lower_bound); data = solver->column; for (j = 0; j <= k; j++, data++) printf(" %d : % 4d(% 2d % 2d)\n", j, data->v, data->i, data->w); printf("\n"); } } if (debug == 2) { printf("i=%d:\n", solver->n - 1); data = solver->column; for (j = 0; j <= k; j++, data++) printf(" % 4d(% 2d % 2d)\n", data->v, data->i, data->w); } if (debug > 0) printf("loops count: %u\n", counter); } static void reset_output(char *output, int bits) { char *ch; char *end; end = output + bits; for (ch = output; ch < end; ) { (*ch++) = '0'; (*ch++) = ' '; } ch--; *ch = '\0'; } static int print(Solver* solver) { int ret; int v, w; char *output; const Item *item; const SolverData *data; output = calloc((solver->n * 2), sizeof(char)); if (!output) { fprintf(stderr, "ERROR: output calloc\n"); return EXIT_FAILURE; } reset_output(output, (solver->n * 2)); data = solver->column + solver->k; printf("%d %d\n", data->v, 0); v = 0; w = 0; /* for (data = solver->column + solver->k; data->i != -1 ; data -= item->w) */ for (data = solver->column + solver->k; data->s != -1 ; data -= item->w) { /* item = &solver->items[data->i]; */ item = &solver->items[data->s]; output[(item->i) * 2] = '1'; if (debug > 1) printf(" from % 6d - take % 4d (% 4d % 4d)\n", data->v, item->i, item->v, item->w); v += item->v; w += item->w; } printf("%s\n", output); free(output); ret = EXIT_SUCCESS; data = solver->column + solver->k; if (v != data->v) { fprintf(stderr, "ERROR: value %d != %d\n", v, data->v); ret = EXIT_FAILURE; } if (w > solver->k) { fprintf(stderr, "ERROR: weight %d > %d\n", w, solver->k); ret = EXIT_FAILURE; } return ret; } static int check(Solver *solver, int excpected_value) { const SolverItem *data; if (excpected_value == NONE) return EXIT_SUCCESS; data = solver->column + solver->k; if (data->v != excpected_value) { fprintf(stderr,"*** ERROR found %d != %d excpected !", data->v, excpected_value); return EXIT_FAILURE; } return EXIT_SUCCESS; } int main(int argc, char** argv, char** env) { FILE *fp; int ret; int opt; int i; int excpected_value; uint64_t dt; struct timespec t0; struct timespec t1; Solver solver; InputItem *item; debug = 0; sort = UNSORTED; sort_order = SORT_DESC; excpected_value = NONE; while ((opt = getopt(argc, argv, "d:e:s:S")) != -1) { switch (opt) { case 'd': debug = atoi(optarg); break; case 'e': excpected_value = atoi(optarg); break; case 's': sort = atoi(optarg); break; case 'S': sort_order = SORT_ASC; break; default: /* '?' */ fprintf(stderr, "Usage: %s [falgs] input\n", argv[0]); return EXIT_FAILURE; } } if (optind >= argc) { fprintf(stderr,"input file missing\n"); return EXIT_FAILURE; } if (sort > SORT_RV) sort = UNSORTED; if (sort_order > SORT_ASC) sort = SORT_DESC; if (debug > 0) printf("%s\n", argv[optind]); fp = fopen(argv[optind], "r"); if (fp == NULL) { fprintf(stderr, "I couldn't open results.dat for reading.\n"); return EXIT_FAILURE; } /* read k and n */ if (fscanf(fp, "%d %d\n", &solver.n, &solver.k) != 2) { fprintf(stderr, "ERROR: read first line\n"); return EXIT_FAILURE; } if (debug > 0) printf(" K:%d N:%d\n", solver.k, solver.n); /* allocate */ solver.items = calloc(solver.n, sizeof(InputItem)); if (!solver.items) { fprintf(stderr, "ERROR: items calloc\n"); return EXIT_FAILURE; } solver.column = calloc((solver.k + 1), sizeof(SolverItem)); if (!solver.column) { free(solver.items); fprintf(stderr, "ERROR: column calloc\n"); return EXIT_FAILURE; } for (i = 0; i < (solver.k + 1); i++) { solver.column[i].i = NONE; } /* read items */ solver.w_sum = 0; item = solver.items; for (i = 0; i < solver.n; i++, item++) { item->i = i; fscanf(fp, "%d %d\n", &item->v, &item->w); solver.w_sum += item->w; } fclose(fp); if (sort != UNSORTED) qsort(solver.items, solver.n, sizeof(InputItem), item_cmp); if (debug > 1) { printf(" Items "); if (sort == UNSORTED) { printf("unsorted\n"); } else { printf("sorted "); switch(sort){ case SORT_VR: printf("Value,ratio(V/W)"); break; case SORT_WR: printf("Weight,ratio(V/W)"); break; case SORT_RW: printf("ratio(V/W),Weight"); break; case SORT_RV: printf("ratio(V/W),Value"); break; default: break; } if (sort_order == SORT_ASC) printf(" asc\n"); else printf(" desc\n"); } item = solver.items; printf(" index Value Weight (sum %d)\n", solver.w_sum); for (i = 0; i < solver.n; i++, item++) printf(" % 8d % 8d % 8d\n", item->i, item->v, item->w); } clock_gettime(CLOCK_MONOTONIC, &t0); solve(&solver); clock_gettime(CLOCK_MONOTONIC, &t1); ret = check(&solver, excpected_value); if (debug > 0) { dt = ((t1.tv_sec * 1000000000) + t1.tv_nsec) - ((t0.tv_sec * 1000000000) + t0.tv_nsec); printf(" time %7u [ms]\n", (unsigned int)(dt/1000000)); } free(solver.items); free(solver.column); return ret; }