/* Problem 5--Substitution Cipher A way that's not too bad is to go through the words and build a table to guess alphabetical order between letters. Then go through the table to see which letters are guessable. */ #include #include #include int table[26][26], wct, letters; FILE *in, *out; char words[20][22], decode[26], message[52]; int main (int argc, char **argv); void FillTable (void); int main (int argc, char **argv) { int cases, i, j, good; in = fopen ("prob5.in","r"); out = fopen ("prob5.out","w"); fscanf (in,"%d",&cases); /* get cases */ for (i=0; i < cases; i++) { fscanf (in,"%d %d",&letters,&wct); /* get alphabet and words */ memset (table,-1,sizeof table); /* Initialize table with -1's */ fgets (words[0],22,in); for (j=0; j < wct; j++) { fgets (words[j],22,in); words[j][strlen(words[j])-1] = 0; } FillTable (); fgets (message,52,in); message[strlen(message)-1] = 0; good = 1; for (j=0; good && j < (int)strlen (message); j++) { if (message[j] >= 'a' && message[j] <= 'a'+letters-1) { if (decode[message[j]-'a'] == '?') good = 0; /* unknown character */ else message[j] = decode[message[j]-'a']; } } if (good) fprintf (out,"%s\n",message); else fprintf (out,"Message cannot be decrypted.\n"); } fclose (in); fclose (out); return EXIT_SUCCESS; } /* The table is filled as follows. table[i][j] is 1 if i is known to precede j. It is 0 if i is known not to precede j. It is -1 if this information is not available. The letter that 0 things precede must be a. The letter that 1 thing precedes must be b, and so forth. */ void FillTable (void) { int i, j, k, ii, jj, kk, ch; for (i=0; i < letters; i++) table[i][i]=0; /* no letter precedes self*/ for (i=0; i < wct-1; i++) for (j=i+1; j < wct; j++) {/*skip if one word is a prefix of another*/ if (memcmp (words[i],words[j],strlen (words[i]))==0) continue; for (k=0; words[i][k]==words[j][k]; k++); /* find first diff letter*/ table[words[i][k]-'a'][words[j][k]-'a'] = 1; /* set table */ table[words[j][k]-'a'][words[i][k]-'a'] = 0; } do { /* Apply transitive closure to this table */ ch = 0; for (ii=0;ii