算法ABBA(SRM 663,DIV 2,500)

时间:2016-04-12 13:01:55

标签: algorithm brute-force

我正在从this blog

处理问题
  

有一天,杰米注意到许多英文单词只使用字母A和B.这类单词的例子包括“AB”(腹部的缩写),“BAA”(羊的噪音),“AA”(a熔岩类型)和“ABBA”(瑞典流行音乐)。

     

受这种观察的启发,杰米创造了一个简单的游戏。你有两个字符串:初始和目标。游戏的目标是找到一系列有效的动作,这些动作将初始变为目标。有两种类型的有效移动:

     

将字母A添加到字符串的末尾   反转字符串,然后将字母B添加到字符串的末尾。   如果存在将初始变为目标的一系列有效移动,则返回“可能”(为清晰起见)。否则,返回“不可能”。

我的问题:

  1. 我的解决方案遵循示例步骤:首先,反向并追加'B',然后追加'A'。我不知道是否需要使用该步骤的另一个顺序(首先,附加'A',然后反向并追加'B')。
  2. 我得到“ABBA”,应该返回“可能”,但“不可能”被归还。
  3. public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println(canContain("B","ABBA"));
    }
    
    public static String canContain(String Initial, String Target){ 
    
        char[] target = new char[1000];
        char[] initial1 = new char[1000];
        int flag = 0;
        boolean possible = false;
        int InitialLength = Initial.length();
        int TargetLength = Target.length();
    
        System.out.println("Initial:");
        int countInitial = -1;
        for(char x : Initial.toCharArray()){
            countInitial++;
            if(x=='A')initial1[countInitial]='A';
            if(x=='B')initial1[countInitial]='B';
            System.out.print(x+"->"+initial1[countInitial]+" ");
        }
    
    
        int countTarget = -1;
        System.out.println("\nTarget:");
        for(char y : Target.toCharArray()){
            countTarget++;
            if(y=='A')target[countTarget]='A';
            if(y=='B')target[countTarget]='B';
            System.out.print(y+"->"+target[countTarget]+" ");
        }
        System.out.print("\n");
    
    
    
        //Check Initial char[]
        System.out.print("---------------");
        System.out.print("\n");
        for(int t1 = 0; t1 <= countInitial; t1++){
            System.out.print(initial1[t1]+"-");
        }
        System.out.print("\n");
        for(int t3 = 0; t3 <= countTarget; t3++){
            System.out.print(target[t3]+"-");
        }
    
        while(countInitial != countTarget){
            if(flag == 0 && Initial != Target){
                System.out.println("\n_______A_______");
                countInitial++;
                System.out.println("countInitial = "+countInitial);
                initial1[countInitial] = 'A';
                System.out.println(initial1[countInitial]);
                for(int t1 = 0; t1 <= countInitial; t1++){
                    System.out.print(initial1[t1]+"-");
                }
                flag = 1;
            }else if(flag == 1 && Initial != Target){
                System.out.println("\n_______R_+_B_______");
                int ct = 0;
                char[] temp = new char[1000];
                for(int i = countInitial; i >= 0; i--){
                    System.out.println("countInitial = "+countInitial);
                    temp[ct] = initial1[i];
                    System.out.println("ct = "+ct);
                    ct++;
                }
                initial1 = temp;
                countInitial++;
                initial1[countInitial] = 'B';
                for(int t1 = 0; t1 < countInitial; t1++){
                    System.out.print(initial1[t1]+"-");
                }
                flag = 0;
            }
        }
    
        if(initial1.equals(target)){
            return "Possible";
        }else{
            return "Impossible";
        }
    
    }
    

3 个答案:

答案 0 :(得分:1)

您当前的问题是您按特定顺序应用规则。但是,不禁止连续多次使用相同的规则。因此,要从初始化获取目标字符串,您需要检查所有可能的规则应用程序序列。这被称为组合爆炸。

这样的问题通常更容易解决倒退工作。如果目标字符串为xyzA,则只能通过xyz中的规则1获取。如果目标字符串为xyzB,则只能通过zyx的规则2获取。所以在伪代码中,

    while length(target) > length(initial)
        remove the last letter from target
        if removed letter is "B"
            reverse target
    if target == initial
        print "Possible"
    else
        print "Impossible"

当然,逆转不一定要明确。

答案 1 :(得分:0)


这是一个将运行线性时间O(n)的解决方案。我们的想法是从目标字符串开始并尝试恢复操作,直到找到与初始字符串长度相同的字符串。然后你比较这两个字符串。这是解决方案:

   private static final char A = 'A';
   private static final String POSSIBLE = "Possible";
   private static final String IMPOSSIBLE = "Impossible";

   public String canObtain(String initial, String target) {
      if (initial == null ||
            initial.trim().length() < 1 ||
            initial.trim().length() > 999) {
         return IMPOSSIBLE;
      }

      if (target == null ||
            target.trim().length() < 2 ||
            target.trim().length() > 1000) {
         return IMPOSSIBLE;
      }

      return isPossible(initial, target) ? POSSIBLE : IMPOSSIBLE;
   }

   private boolean isPossible(String initial, String target) {
      final StringBuilder sb = new StringBuilder(target);
      while (initial.length() != sb.length()) {
         char targetLastChar = sb.charAt(sb.length() - 1);
         if (targetLastChar == A) {
            unApplyA(sb);
         } else {
            unApplyRevB(sb);
         }
      }

      return initial.equals(sb.toString());
   }

   private void unApplyA(StringBuilder sb) {
      sb.deleteCharAt(sb.length() - 1);
   }

   private void unApplyRevB(StringBuilder sb) {
      sb.deleteCharAt(sb.length() - 1);
      sb.reverse();
   }

答案 2 :(得分:0)

晚了一点,但这是Python中的一个简洁的解决方案,它可以线性运行:

class ABBA:
    def canObtain(self, initial, target):
        if initial == target:
            return 'Possible'
        if len(initial) == len(target):
            return 'Impossible'
        if target[-1] == 'A':
            return self.canObtain(initial, target[:-1])
        if target[-1] == 'B':
            return self.canObtain(initial, target[:-1][::-1])