/****** Problem 2--Cycles, Period. ************************************ I thought this was the hardest problem of the bunch. Others may disagree with me. What made this problem hard was seeing all the checks that had to be made. In particular, the sample data given in the problem description did not test all of these cases. First of all, there is no limit given on the number of observations, so this had to be handled dynamically; I used a linked list. Then, when all the data had been read in (and there is no guarantee that this data will be sorted in any particular order), possible cycle lengths are found by seeing which observations recorded the same value. Since all values are unique within a period, the difference in observation times of the same value must be a multiple of the period. Thus, to find the greatest possible period, you need to compute the greatest common factor of all of these potential periods. Finally, it is very possible that there is no period at all in the data. Once you figure out what the period could be, you have to go through and make sure that all of the data does indeed abide by this period; if two observation times differ by a multiple of the cycle length, yet the values observed are different, there is no observable cycle, and this should be reported. Additionally, if there is no repetition in the data, there is also no observable cycle. The test data supplied gives an example of the latter problem, but not one of the former. **********************************************************************/ #include #include typedef struct pairlist *pairlistptr; typedef struct pairlist { /* linked list for pairs */ int t, v; pairlistptr next; } pairlist; int main (int argc, char **argv); static pairlistptr readlist (void); static int GCF (int a, int b); static int maxcyclelength (pairlistptr p); static int verify (pairlistptr p, int len); static int cycle (pairlistptr p); static void freelist (pairlistptr p); FILE *in, *out; /****** main ********************************************************** This program repeatedly reads in a list of observation times and values and determines if a cycle is present. If there is one, it prints the length of the greatest possible cycle. If not, it prints a message to that effect. The program ends when an empty list is provided. **********************************************************************/ int main (int argc, char **argv) { int c, /* computed cycle length */ cs; /* case number */ pairlistptr p; /* the list of observations */ in = fopen ("prob2.in","r"); /* redirect input and output */ out = fopen ("prob2.out","w"); for (cs=0;(p=readlist())!=NULL;) { /* read in a list */ /* done if an empty list is read */ if ((c = cycle (p))>0) /* print computed cycle time */ fprintf (out,"Case %d: cycle time = %d.\n",++cs,c); else fprintf (out,"Case %d: no cycle time can be determined.\n",++cs); freelist (p); /* free up our linked list */ } fclose (in); /* close our files */ fclose (out); return EXIT_SUCCESS; } /***** readlist ******************************************************* readlist reads in a linked list of ordered pairs. The routine is standard. Note that we are not guaranteed any specific order of the pairs in the listing, thus it won't make any difference that they appear in the linked list in the opposite order of entry. **********************************************************************/ static pairlistptr readlist (void) { pairlistptr p, /* The list of pairs (to be returned) */ q; /* temporary */ int t, v; /* The input values to be added to the list */ for (p=NULL;;) { fscanf (in,"%d %d",&t,&v); if (t==0 && v==0) break; /* if both are 0, then the list is done */ q = malloc (sizeof (pairlist)); q->t = t; /* add data to beginning of list */ q->v = v; q->next = p; p = q; } return p; } /****** GCF *********************************************************** GCF compute the greatest common factor of two integers. The algorithm below is Euclid's algorithm, the easiest method of computing it. **********************************************************************/ static int GCF (int a, int b) { return b==0 ? a : GCF (b, a%b); } /********* maxcyclelength ********************************************* maxcyclelength accepts a list of pairs and returns the GCF of all potential cycles in the list. If there is no repetition of data in the list, this function returns 0. This function simply uses nested loops to try every pair of values in the list to see if there is a potential cycle. **********************************************************************/ static int maxcyclelength (pairlistptr p) { int len; /* the cycle length (to be returned) */ pairlistptr q, r; /* loop iterators */ len = 0; for (q=p;q!=NULL;q=q->next) /* q loops from p to the end */ for (r=q->next;r!=NULL;r=r->next) /* r loops from one past q to the end */ if (q->v == r->v) /* compute the GCF of this cycle with all */ len = GCF (len,abs(q->t-r->t)); /* previously found cycles. */ return len; } /******* verify ******************************************************* verify accepts a list of pairs and a potential cycle length and determines whether that cycle length could possibly work. What it does is check whether there are any pairs that are a full number of cycles apart but still have a different value. verify returns true if the cycle length is valid, false otherwise. This function simply uses nested loops to check whether all pairs of observations are consistent with this cycle length. **********************************************************************/ static int verify (pairlistptr p, int len) { int b; /* boolean value (to be returned) */ pairlistptr q, r; /* loop iterators */ b = 1; for (q=p;q!=NULL && b;q=q->next) /* q goes from p to the end, but the loop will abort */ /* early if b ever becomes 0 */ for (r=q->next;r!=NULL && b;r=r->next) /* r goes from q to the end, but the loop will abort */ /* early if b ever becomes 0 */ b = abs(q->t-r->t)%len != 0 || q->v == r->v; /* check for validity of the pairs at q and r */ return b; } /******* cycle ******************************************************** cycle computes the maximum cycle length supported by input data in p. if no cycle is supported, this function returns 0. **********************************************************************/ static int cycle (pairlistptr p) { int c; /* the cycle length */ c = maxcyclelength (p); /* the max cycle length */ if (c > 0 && !verify (p,c)) /* if this length is not borne out */ c = 0; /* by the data, we must assume there */ return c; } /******* freelist ***************************************************** freelist releases the data structure. Since this routine provides no functionality and is included only to avoid memory leaks, you may wish to avoid coding this routine in a situation in which time is of the essence. **********************************************************************/ static void freelist (pairlistptr p) { if (p != NULL) { freelist (p->next); free (p); } }