되는대로 살자

[C언어 기출문제&풀이] Crypt Kicker 본문

2009~2014/C/C++

[C언어 기출문제&풀이] Crypt Kicker

malu 2011. 5. 31. 18:21


문제: 텥ㄱ스트를 암호화하는 방법 중에 보안상 취약하긴 하지만 흔하게 쓰이는 방법으로 알파벳 글자를 다른 글자로 돌리는 방법이 있다. 즉 알파벳의 각 글자를 다른 글자로 치환하낟. 암호화된 것을 닷 원래대로 되돌릴 수 있으려면 두 개의 서로 다른 글자가 같은 글자로 치환되지 않아야 한다.

암호화된 텍스트가 한 줄 이상 입력되는데, 각 줄마다 서로 다른 치환 방법이 적용된다고 가정하자.
암호화 이전의 텍스트에 있는 단어는 모두 주어진 사전에 들어있는 단어라고 가정하고, 암호화된 텍스트를 해독하여 원래 텍스트를 알아내자.

임력: 입력은 한 개의 정수 n이 들어있는 행으로 시작되며 그 다음 줄부터는 한 줄에 하나씩 n개의 소문자로 쓰인 단어들이 알파벳 순으로 입력된다. 이 n개의 단어들은 복호화된 텍스트에 들어갈 수 있는 단어로 구성된 사전이다. 사전 뒤에는 몇 줄의 텍스트가 입력된다. 각 줄은 앞에서 설명했던 방법에 따라 암호화된다.
사전에 들어갈 수 있는 단어읭 개수는 1000개를 넘지 않는다. 단어의 길이는 16글자를 넘지 않는다. 암호화된 텍스트에는 소문자와 스페이스만 들어가며 한 줄의 길이는 80 글자를 넘어가지 않는다.

출력: 각 줄을 복호화하여 표준 출력으로 출력한다. 여러 문장으로 복호화될 수 있다면 그 중 아무 결과나 출력하면 된다. 가능한 풀이가 없다면 알파벳 모든 문자를 아스테리스크로 바꾸면 된다.
문제 풀이: 입력받은 단어를 dic[]에 저장하고, 단어를 매치시켜본다 조건은 두가지가 만족되어야 하는데 1. 한 문자가 ㄷ서로 다른 두 문자로 매핑되어서는 안된다.
2. 서로 다른 두 문자가 같은 문자로 매핑될 수 없다.
소스코드

#include <stdio.h>

#include <string.h>

#define MAX_DIC_SIZE 1000
#define MAX_LINE_LENGTH 80
#define MAX_WORD_LENGTH 16

static char dic[MAX_DIC_SIZE][MAX_WORD_LENGTH +1];
static char line[MAX_LINE_LENGTH+1];
static unsigned int dic_size;
static unsigned int line_len;

int search(unsigned int k, char *map, char *inv)
{
 char word[MAX_WORD_LENGTH +1];
 char map2['z' + 1],inv2['z'+1];
 unsigned int i,j,t;
 char c;
 while(line[k] == ' ')
  k++;

 if(k >= line_len)
 {
  for(i=0;i<line_len;i++)
   putchar(line[i]==' '?' ': map[line[i]]);
  putchar('\n');
  return 1;
 }
 //k번째 위치 이후의 첫번째 단어를 찾아낸다.
 for(t=0;line[k+t] >='a' && line[k+t] <= 'z';t++)
  word[t] = line[k+t];
 word[t] = '\0'; //단어가 끝나고 NULL 로 지정
 for(i=0;i<dic_size;i++)
  //사전에서 길이가 같은 단어를 검색
  if(strlen(dic[i]) == t)
  {
   for(c='a'; c<='z';c++)
   {
    map2[c] = map[c]; //c번째 글자를 매핑
    inv2[c] = inv[c]; // 역반환 저장
   }
  }
  //word를 dic[i]에 일치시키면서, mapping의
  //일관성이 유지되는지 검사
  for(j=0;j<t;j++) // t=k번째 위치 이후의 첫번째 단어의 길이
  {
   //검사하고자하는 단어의 j번째 문자가 이미 기록되어 있고
   // '' 가 이 단어와 매치가 되지 않을 때
   if(map2[word[j]] && map2[word[j]] !=dic[i][j]
    || inv2[dic[i][j]] && inv2[dic[i][j]] != word[j])
    goto end_of_loop_i;
   else
   {
    map[word[j]] = dic[i][j];
    inv2[dic[i][j]] = word[j];
   }

   if(search(k+t,map2, inv2))
    return 1;
end_of_loop_i: ;
  }
  return 0;
}
int main()
{
 char map['z'+1], inv['z'+1];
 unsigned int i;

 scanf("%d",&dic_size);
 gets(line);
 for(i=0;i<dic_size;i++)
  gets(dic[i]);
 while(gets(line) && *line !=EOF)
 {
  line_len = strlen(line);
  for(i='a';i<='z';i++)
  {
   map[i] = '\0';
   inv[i] = '\0';
  }
  if(!search(0,map,inv))
  {
   for(i=0;i<line_len;i++)
    putchar(line[i] == ' ' ? ' ': '*');
   putchar('\n');
  }
 }
}