C 언어 로 문자열 의 전체 배열 문 제 를 해결 합 니 다.

문제.
문자열 을 입력 하여 이 문자열 의 모든 배열 을 인쇄 합 니 다.예 를 들 어 문자열 abc 를 입력 하면 문자 a,b,c 가 배열 할 수 있 는 모든 문자열 abc,acb,bac,bca,cab 와 cba 를 출력 합 니 다.
사고의 방향
이것 은 전형 적 인 귀속 구 해 문제 로 귀속 알고리즘 은 네 가지 특성 이 있다.
  •     반드시 도달 할 수 있 는 종료 조건 이 있어 야 한다.그렇지 않 으 면 프로그램 이 사 순환
  • 에 빠진다.
  •     하위 문 제 는 규모 적 으로 원래 문제 보다
  • 작다.
  •     하위 문 제 는 재 귀적 호출 을 통 해
  • 을 풀 수 있다.
  •     하위 문제 의 해 는 전체 문제 의 해
  • 으로 조합 할 수 있어 야 한다.
    질문
    n-1 개 원소 의 전체 배열 을 생 성 할 수 있다 면 n 개 원소 의 전체 배열 을 생 성 할 수 있다.하나의 원소 만 집합 하면 전체 배열 을 직접 생 성 할 수 있다.그래서 전체 배열 의 재 귀 중지 조건 이 명확 하고 하나의 요소 만 있 을 때.우 리 는 전체 배열 의 과정 을 분석 할 수 있다.
  •     우선,우 리 는 첫 번 째 문자 a 를 고정 시 키 고 뒤의 두 문자 bc 의 배열
  • 을 구 합 니 다.
  •     두 글자 의 bc 배열 이 잘 된 후에 우 리 는 첫 번 째 문자 a 와 뒤의 b 를 교환 하여 bac 를 얻 었 다.이어서 우 리 는 첫 번 째 문자 b 를 고정 시 키 고 뒤의 두 글자 ac 의 배열
  • 을 구 했다.
  •     지금 은 c 를 첫 번 째 위치 에 놓 을 때 입 니 다.그러나 앞에서 우 리 는 원래 의 첫 번 째 문자 a 와 뒤의 b 를 교환 했다 는 것 을 기억 하 세 요.이번 c 는 원래 의 첫 번 째 위치 에 있 던 a 와 교환 하기 위해 서 우 리 는 c 와 첫 번 째 문 자 를 교환 하기 전에 먼저 b 와 a 를 교환 해 야 합 니 다.b 와 a 를 교환 한 후에 c 와 첫 번 째 위치 에 있 는 a 를 교환 하여 cba 를 얻 습 니 다.우 리 는 첫 번 째 문자 c 를 다시 고정 시 키 고 뒤의 두 글자 b,a 의 배열
  • 을 구 합 니 다.
  •     우리 가 세 글자 의 배열 을 어떻게 구 하 는 지 이미 알 고 있 는 이상 첫 번 째 문 자 를 고정 한 후에 뒤의 두 글자 의 배열 을 구 하 는 것 은 전형 적 인 재 귀 사고 이다.
  • 아래 의 이 그림 은 재 귀 과정 을 분명하게 보 여 주 었 다.
    2015815112832632.png (805×385)
    기본 적 인 해결 방법
    방법 1:최종 배열 의 첫 번 째 문자 로 문자열 에서 문 자 를 순서대로 꺼 내 고 나머지 문자 로 구 성 된 문자열 에 대해 전체 배열 을 생 성 합 니 다.최종 결 과 는 꺼 낸 문자 와 나머지 하위 문자열 을 모두 배열 하 는 조합 입 니 다.
    
    #include <iostream>
    #include <string>
    using namespace std;
     
    void permute1(string prefix, string str)
    {
      if(str.length() == 0)
        cout << prefix << endl;
      else
      {
        for(int i = 0; i < str.length(); i++)
          permute1(prefix+str[i], str.substr(0,i)+str.substr(i+1,str.length()));
      }
    }
     
    void permute1(string s)
    {
      permute1("",s);
    }
     
    int main()
    {
      //method1, unable to remove duplicate permutations.
      cout << "method1" << endl;
      permute1("ABA");
    }
    
    장점:이 방법 은 이해 하기 쉽 지만 중복 되 는 배열 을 제거 할 수 없습니다.예 를 들 어 s="ABA"는 두 개의"AAB"를 생 성 합 니 다.
    방법 2:교환 하 는 사상 을 이용 하여 구체 적 으로 실례 를 보지 만 이 방법 은 방법 1 보다 이해 하기 쉽다.
    2015815112903993.gif (400×320)
    
    #include <iostream>
    #include <string>
    #include <cstdio>
    using namespace std;
     
    void swap(char* x, char* y)
    {
      char tmp;
      tmp = *x;
      *x = *y;
      *y = tmp;
    }
     
    /* Function to print permutations of string
      This function takes three parameters:
      1. String
      2. Starting index of the string
      3. Ending index of the string. */
    void permute(char *a, int i, int n)
    {
      int j;
      if (i == n)
       printf("%s
    ", a); else { for (j = i; j <= n; j++) { if(a[i] == a[j] && j != i) // ,    continue; swap((a+i), (a+j)); permute(a, i+1, n); swap((a+i), (a+j)); //backtrack } } } int main() { //method2 cout << "method2" << endl; char a[] = "ABA"; permute(a,0,2); return 0; }
    두 가지 방법의 생 성 결과:
    
    method1
    ABA
    AAB
    BAA
    BAA
    AAB
    ABA
    method2
    ABA
    AAB
    BAA
    
    
    다음은 ACM 제목 인 스 턴 스 를 살 펴 보 겠 습 니 다.
    예제 문제
    제목 설명
        제목 설명: 
        서로 다른 소문 자로 구 성 된 문자열 을 지정 하고 이 문자열 의 모든 배열 을 출력 합 니 다. 
        우 리 는 소문 자 에 대해'a','b','y','z'가 있다 고 가정 합 니 다.그리고 주어진 문자열 의 자 모 는 이미 어 릴 때 부터 큰 순서 로 배열 되 었 습 니 다. 
        입력: 
        입력 은 한 줄 뿐 입 니 다.소문 자로 구 성 된 문자열 입 니 다.문자열 의 길 이 는 1 에서 6 사이 입 니 다. 
        출력: 
        이 문자열 의 모든 배열 방식 을 출력 합 니 다.줄 마다 배열 합 니 다.알파벳 순 서 를 비교적 작은 것 으로 앞 에 배열 해 야 한다.알파벳 순 서 는 다음 과 같다. 
        S=s1s 2...sk,T=t1t 2...tk 를 알 고 있 으 면 S    s1=t1,s2=t2,...,sp-1=tp-1,sp    샘플 입력: 
        abc 
        샘플 출력: 
        abc 
        acb 
        bac 
        bca 
        cab 
        cba 
        알림: 
        각 그룹의 샘플 출력 이 끝 난 후에 다시 차 를 출력 해 야 한다.
        ac 코드
       
    
     #include <stdio.h> 
      #include <stdlib.h> 
      #include <string.h> 
        
      struct seq 
      { 
        char str[7]; 
      }; 
        
      struct seq seqs[721]; 
      int count; 
        
      void swap(char *str, int a, int b) 
      { 
        char temp; 
        temp = str[a]; 
        str[a] = str[b]; 
        str[b] = temp; 
      } 
        
      void permutation_process(char *name, int begin, int end) { 
        int k; 
        
        if (begin == end - 1) { 
          strcpy(seqs[count].str, name); 
          count ++; 
        }else { 
          for (k = begin; k < end; k ++) { 
            swap(name, k, begin); 
            permutation_process(name, begin + 1, end); 
            swap(name, k, begin); 
          } 
        } 
      } 
        
      int compare(const void *p, const void *q) 
      { 
        const char *a = p; 
        const char *b = q; 
        return strcmp(a, b); 
      } 
        
      int main() 
      { 
        char name[7]; 
        int i, len; 
        
        while (scanf("%s", name) != EOF) { 
          count = 0; 
          len = strlen(name); 
          permutation_process(name, 0, len); 
          qsort(seqs, count, sizeof(seqs[0]), compare); 
        
          for (i = 0; i < count; i ++) { 
            printf("%s
    ", seqs[i].str); } printf("
    "); } return 0; }
           
        /**************************************************************
            Problem: 1120
            User: wangzhengyi
            Language: C
            Result: Accepted
            Time:710 ms
            Memory:920 kb
        ****************************************************************/ 
    중복 되 는 전체 배열 을 제거 합 니 다.
    상기 코드 에 결함 이 있 습 니 다.바로 중복 데이터 의 출력 을 초래 할 수 있 습 니 다.예 를 들 어 abb 와 같은 문자열 입 니 다.상기 프로그램 이 끝 난 결 과 는 그림 과 같 습 니 다.
    2015815112950326.png (564×150)
    전체 배열 은 첫 번 째 숫자 부터 시작 해서 모든 숫자 가 그 뒤의 숫자 와 교환 되 기 때문에 우 리 는 먼저 이런 판단 을 추가 하려 고 한다.만약 에 하나의 숫자 가 뒤의 숫자 와 같다 면 이 두 수 는 교환 하지 않 을 것 이다.예 를 들 어 abb,첫 번 째 수 와 뒤의 두 수 를 바 꾼 bab,bba.그리고 abb 에서 두 번 째 수 는 세 번 째 수 와 같 으 면 교환 할 필요 가 없습니다.그러나 bab 에 대해 서 는 두 번 째 수 와 세 번 째 수가 다 르 면 바 바 를 교환 해 야 한다.이곳 의 바 바 와 첫 번 째 수 는 세 번 째 수 와 교환 한 결과 가 같 기 때문에 이 방법 은 안 된다.
    다른 사고방식 으로 abb 에 대해 첫 번 째 수 a 와 두 번 째 수 b 를 교환 하여 bab 를 얻 은 다음 에 첫 번 째 수 와 세 번 째 수의 교환 을 고려한다.이때 세 번 째 수 는 두 번 째 수 와 같 기 때문에 첫 번 째 수 는 세 번 째 수 와 교환 하지 않 는 다.bab 를 고려 하면 두 번 째 수 와 세 번 째 수 를 교환 하면 bba 를 해결 할 수 있 습 니 다.이때 전체 배열 생 성 완료!
    이렇게 해서 우 리 는 전체 배열 에서 중복 되 는 규칙 을 없 애 야 한다.
    무 거 운 것 을 없 애 는 모든 배열 은 첫 번 째 숫자 부터 모든 숫자 가 그 뒤에 반복 되 지 않 는 숫자 와 교환 하 는 것 이다.
    위 에 ac 코드 를 붙 인 리 셋 버 전:
       
    
     #include <stdio.h> 
      #include <stdlib.h> 
      #include <string.h> 
       
      struct seq 
      { 
        char str[7]; 
      }; 
       
      struct seq seqs[721]; 
      int count; 
       
      int is_swap(char *str, int begin, int k) 
      { 
        int i, flag; 
       
        for (i = begin, flag = 1; i < k; i ++) { 
          if (str[i] == str[k]) { 
            flag = 0; 
            break; 
          } 
        } 
       
        return flag; 
      } 
       
      void swap(char *str, int a, int b) 
      { 
        char temp; 
        temp = str[a]; 
        str[a] = str[b]; 
        str[b] = temp; 
      } 
       
      void permutation_process(char *name, int begin, int end) { 
        int k; 
       
        if (begin == end - 1) { 
          strcpy(seqs[count].str, name); 
          count ++; 
        }else { 
          for (k = begin; k < end; k ++) { 
            if (is_swap(name, begin, k)) { 
              swap(name, k, begin); 
              permutation_process(name, begin + 1, end); 
              swap(name, k, begin); 
            } 
          } 
        } 
      } 
       
      int compare(const void *p, const void *q) 
      { 
        const char *a = p; 
        const char *b = q; 
        return strcmp(a, b); 
      } 
       
      int main() 
      { 
        char name[7]; 
        int i, len; 
       
        while (scanf("%s", name) != EOF) { 
          count = 0; 
          len = strlen(name); 
          permutation_process(name, 0, len); 
          qsort(seqs, count, sizeof(seqs[0]), compare); 
       
          for (i = 0; i < count; i ++) { 
            printf("%s
    ", seqs[i].str); } printf("
    "); } return 0; }

    좋은 웹페이지 즐겨찾기