UVa Problem Solution: 843 - Crypt Kicker


This is the hardest problem ever since in this book. After some thinking, I realized that this problem can be solved with backtracking. After some more thinking, I realized that we should backtrack the cipher, i.e., the decrypt table along with the encrypt table. Unfortunately, one day has passed after these thinking.

The search procedure can be accelerated by three means: 
  1) index the dictionary by word length,
  2) associate each word with a signature that specify the word's character pattern, and
  3) sort the words by length in reverse order.

Code:
  1. /*************************************************************************
  2.  * Copyright (C) 2008 by liukaipeng                                      *
  3.  * liukaipeng at gmail dot com                                           *
  4.  *************************************************************************/
  5. /* @JUDGE_ID 00000 843 C "Crypt Kicker" */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <strings.h>
  10.                
  11. #define WORDSIZE 17
  12. #define LINESIZE 81
  13. #define NLINEWORDS (LINESIZE/2)
  14. #define NWORDS 1000
  15. #define NCHARS 128
  16. /*************************************************************************
  17.  * Stack (FILO)                                                          *
  18.  * Note: No error check is performed.                                    *
  19.  *************************************************************************/
  20. #define STACKSIZE NWORDS
  21. /* a cipher; used for backtracking */
  22. typedef struct cipher
  23. {
  24.   int pos; /* the position of the current text in the line*/
  25.   char decrypt[NCHARS]; /* the decrypt table to current*/
  26.   char encrypt[NCHARS]; /* the encrypt table to current*/
  27. } cipher;
  28. typedef cipher valuetype;
  29. typedef struct stack
  30. {
  31.   size_t top;
  32.   valuetype values[STACKSIZE];
  33. } stack;
  34. void initstack(stack *s)
  35. {
  36.   s->top = 0;
  37. }
  38. int emptystack(stack *s)
  39. {
  40.   return s->top == 0;
  41. }
  42. void pushstack(stack *s, valuetype v)
  43. {
  44.   s->values[s->top++] = v;
  45. }
  46. valuetype popstack(stack *s)
  47. {
  48.   return s->values[--s->top];
  49. }
  50. /*************************************************************************/
  51. typedef int sig_t[WORDSIZE];
  52. /* a word in the dictionary */
  53. typedef struct dictword 
  54. {
  55.   char *word; /* the word */
  56.   sig_t sig; /* the signature of the word */
  57. } dictword;
  58. /* a series of words in the dictionary */
  59. typedef struct dictwords
  60. {
  61.   dictword words[NWORDS];
  62.   int size;
  63. } dictwords;
  64. /* a dictionary indexed by the length of the words */
  65. typedef dictwords dict_t[WORDSIZE];
  66. void read_words(char words[][WORDSIZE], int nwords)
  67. {
  68.   while (nwords-- > 0) {
  69.     gets(words[nwords]);
  70.   }
  71. }
  72. void make_sig(char *s, sig_t sig)
  73. {
  74.   int trans[NCHARS] = {0};
  75.   int i, t;
  76.   for (i = 0, t = 1; s[i] != '/0'; ++i) {
  77.     if (trans[s[i]]) {
  78.       sig[i] = trans[s[i]];
  79.     } else {
  80.       sig[i] = trans[s[i]] = t++;
  81.     }
  82.   }
  83. }
  84. void make_dict(char words[][WORDSIZE], int nwords, dict_t dict)
  85. {
  86.   int i;
  87.   for (i = 0; i < WORDSIZE; ++i) {
  88.     dict[i].size = 0;
  89.   }
  90.   for (i = 0; i < nwords; ++i) {
  91.     dictword dw;
  92.     dw.word = words[i];
  93.     make_sig(dw.word, dw.sig);
  94.     int len = strlen(words[i]);
  95.     dict[len].words[dict[len].size++] = dw;
  96.   }
  97. }
  98. int split(char line[], int size, char *texts[])
  99. {
  100.   int i;
  101.   int ntexts;
  102.   for (i = 0, ntexts = 0; i < size; ++ntexts) {
  103.     texts[ntexts] = line + i;
  104.     for (; line[i] != ' ' && line[i] != '/0'; ++i);
  105.     line[i++] = '/0';
  106.   }
  107.   return ntexts;
  108. }
  109. int strlencmp(void const *x, void const *y)
  110. {
  111.   return strlen(*(char **)y) - strlen(*(char **)x);
  112. }
  113. char *decrypt(dict_t dict, char line[])
  114. {
  115.   int i;
  116.   int size = strlen(line);
  117.   char *texts[LINESIZE];
  118.   /* split the line into words */
  119.   int ntexts = split(line, size, texts);
  120.   /* sort by the word length: longest first */
  121.   qsort(texts, ntexts, sizeof(char *), strlencmp);  
  122.   /* generate the signatures of the words */
  123.   sig_t sigs[NLINEWORDS];
  124.   for (i = 0; i < ntexts; ++i) {
  125.     make_sig(texts[i], sigs[i]);
  126.   }
  127.   
  128.   stack s;
  129.   initstack(&s);
  130.   cipher c = {0, {0}, {0}};
  131.   pushstack(&s, c);
  132.   /* backtracking with the ciphers */
  133.   while (!emptystack(&s) && (c = popstack(&s), c.pos < ntexts)) {
  134.     char *text = texts[c.pos];
  135.     int len = strlen(text);
  136.     dictwords *dws = &dict[len];
  137.     for (i = 0; i < dws->size; ++i) {
  138.       /* check the signature first to avoid unneccesary cipher checking */
  139.       if (memcmp(sigs[c.pos], dws->words[i].sig, len*sizeof(int)) == 0) {
  140.         cipher cc = c;
  141.         char *word = dws->words[i].word;
  142.         int j;
  143.         for (j = 0; j < len; ++j) {
  144.           if (!cc.decrypt[text[j]] && !cc.encrypt[word[j]]) {
  145.             cc.decrypt[text[j]] = word[j];
  146.             cc.encrypt[word[j]] = text[j];
  147.           } else if (cc.decrypt[text[j]] != word[j]) {
  148.             break;
  149.           }
  150.         }
  151.         if (j == len) { /* cipher verified, track it */
  152.           ++cc.pos;
  153.           pushstack(&s, cc);
  154.         }
  155.       } 
  156.     }
  157.   }
  158.   if (c.pos != ntexts) { /* cannot be decrypted */
  159.     memset(c.decrypt, '*', NCHARS);
  160.   }
  161.   c.decrypt['/0'] = ' ';
  162.   
  163.   for (i = 0; i < size; ++i) {
  164.     line[i] = c.decrypt[line[i]];
  165.   }
  166.   return line;
  167. }
  168. int main(int argc, char *argv[])
  169. {
  170. #ifndef ONLINE_JUDGE
  171.   char in[256];
  172.   char out[256];
  173.   strcpy(in, argv[0]);
  174.   strcat(in, ".in");
  175.   strcpy(out, argv[0]);
  176.   strcat(out, ".out");
  177.   if (freopen(in, "r", stdin) == NULL)
  178.     fprintf(stderr, "%s: cannot open input file: %s./n", argv[0], in);
  179.   if (freopen(out, "w", stdout) == NULL)
  180.     fprintf(stderr, "%s: cannot open output file: %s./n", argv[0], out);
  181. #endif
  182.   int nwords;
  183.   scanf("%d/n", &nwords);
  184.   char words[NWORDS][WORDSIZE];
  185.   read_words(words, nwords);
  186.   dict_t dict;
  187.   make_dict(words, nwords, dict);
  188.   char line[LINESIZE];
  189.   while (gets(line) != NULL)
  190.     puts(decrypt(dict, line));
  191.   return 0;
  192. }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值