/* Problem 5--Kissin' Cousins This was probably the hardest one of the bunch. There was an observation that made it easier: If you think of descendant-p as cousin-(-1)-p, you could use the same formula for everything without having to worry about a special case. Also, since no upper limit was given for the number of relatives, this had to be handled dynamically. */ #include #include using namespace std; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) ifstream in ("prob5.in"); ofstream out ("prob5.out"); class relationship; class relationship { //Class for the linked list of names public : char names[2][6]; //Two names int r; //The relationship relationship *next; //The next relationship in the list relationship (char *a, char *b, int r); ~relationship (); }; int main (int argc, char **argv); void AddRelationship (relationship *&head, char *a, char *b, int r); relationship * ScanList (relationship *head, char *a); void GetAncestors (char *a, int p, relationship *&AncList); void GetRelationship (char *a, char *b, int &m, int &n); relationship *RList = NULL; //Master list of relationships /* Relationship constructor function */ relationship::relationship (char *a, char *b, int r) { strcpy (names[0],a); //Add information to the node strcpy (names[1],b); this->r = r; } /* Relationship destructor function */ relationship::~relationship () { if (next != NULL) delete next; //Deallocate every node in list } int main (int argc, char **argv) { char command, line[81], a[6],b[6]; int r; while (true) { in.get(command); //Get the one character command switch (command) { case 'E' : return 0; //Exit program case '#' : in.getline (line, sizeof line); break; //This is a comment; ignore line case 'R' : in.get(a,sizeof a); in.get(b,sizeof b); in >> r; //Get names, relationships, add them AddRelationship (RList,a,b,r); in.getline (line, sizeof line); break; case 'F' : int m,n; //Get names, compute relationship in.get(a,sizeof a); in.get(b,sizeof b); GetRelationship (a,b,m,n); out << a << " and " << b << " are "; switch (m) { case -2 : out << "not related." << endl;break; case -1 : out << "descendant-" << n << "." << endl;break; default : out << "cousin-" << m << "-" << n << "." << endl; } in.getline (line, sizeof line); break; } } delete RList; //Deallocate linked list return 0; } /* AddRelationship simply pushes the new relationship onto the linked list, as a stack. */ void AddRelationship (relationship *&head, char *a, char *b, int r) { relationship *rel = new relationship (a,b,r); rel->next = head; head = rel; } /* ScanList scans the linked list for a particular name, returning NULL if the name isn't there. */ relationship * ScanList (relationship *head, char *a) { if (head==NULL || strcmp (a,head->names[0])==0) return head; return ScanList (head->next,a); } /* GetAncestors builds a linked list of all the ancestors of a given person. a is the person, p is the relationship to the base person, AncList is the list. */ void GetAncestors (char *a, int p, relationship *&AncList) { AddRelationship (AncList,a,"",p); //A person is his own ancestor. for (relationship *P = RList; P != NULL; P = P->next) //Go through list, find an ancestor for this person and make sure //this person hasn't already been added. if (strcmp (P->names[0],a)==0 && ScanList(AncList,P->names[1])==NULL) //Recursively get this guy's ancestors. GetAncestors (P->names[1],p+P->r,AncList); } /* GetRelationship computes the relationship between two individuals. m and n are as defined in the problem. However, if m=-1, it's a descendant relationship. If m=-2, there is no relationship. */ void GetRelationship (char *a, char *b, int &m, int &n) { m = -2; relationship *AncA = NULL; GetAncestors (a,0,AncA); //Get all of a's ancestors. relationship *AncB = NULL; GetAncestors (b,0,AncB); //Get all of b's ancestors. for (relationship *P = AncA; P != NULL; P = P->next) { //Go through all of a's ancestors and see if b shares that ancestor. relationship *Q = ScanList (AncB,P->names[0]); if (Q==NULL) continue; //If not, skip over this guy int tm = MIN (P->r, Q->r)-1, //m is the smallest distance to the //common ancestor. tn = MAX(P->r,Q->r)-tm-1;//n is the difference in the lengths of //the paths. if (m==-2 || tm < m || tm==m && tn < n) { //If this one is closer, m = tm; n = tn;} //remember it. } }