Alice Bob Coin最佳解决方案

时间:2014-02-05 18:33:06

标签: c algorithm

考虑一下我在hackerrank上发现的这个问题: Coins Problem

  
    爱丽丝和鲍勃坐在阳光下;喝橙汁;并观看一些迁徙的鸭子飞往非洲。 “看,”,爱丽丝说,“一个     鸭子在地板上留下了一串金币“。 “大!”     鲍勃喊道,“让我们用这一系列硬币玩游戏。我们会     轮流,我们每个人都会将一枚硬币从“头部”翻转到     “尾巴”状态“。 “好的”,同意爱丽丝并补充道,“但是当我们翻转一枚硬币时,     我们也可以选择在它之后立即翻转硬币,即使这样     硬币是一个“尾巴”,在这种情况下它变成了“头”。 “无论谁能做到     不玩 - 失去“同时哭泣他们两个。狡猾的鲍勃知道     他可以指望诙谐的IEEEXtreme参赛者帮助他获胜。     你可以帮助他吗?任务您的任务是编写一个程序     给出一串H / T字母,计算一个获胜的动作     翻转硬币游戏,如果有,或报告没有获胜     移动,如果是这样的话。获胜的举动是一种合法的举动     要么玩家立即获胜(因为没有更多的硬币)     翻转),否则,在对手的任何后续动作之后有一个     为球员赢得胜利。

  
     

例如,如果输入是TTTT,那么Bob输掉了游戏(没有   “头”所以他不能发挥,因此他输了)。对于输入TTTTHTTTT,   鲍勃通过翻转第五枚硬币获胜;对于输入TTHHT,Bob赢了   翻转两个“头”(第三和第四个硬币);输入   哎呀,鲍勃赢了,如果他翻转硬币2和3。

     

输入要从控制台读取的输入文件包含一行   其中有一个完全由字母H和T组成的字符串,   代表硬币的状态,正如所解释的那样。

     

输出要在控制台写入的输出文件包含一个   线,有一个数字。正数N表示翻转Nth   硬币是一个成功的举动。负数,写为-N,表示   翻转Nth和N + 1个硬币是一个胜利的举动。零,写   0,表示没有获胜动作。注意,一般来说,那里   对于给定的硬币列表,可以是几个获胜的动作。你的计划   可以输出任何一个。

我尝试了一种递归回溯解决方案,但是'C'因Stackoverflow而引发了分段错误错误。这是我的代码:(部分有效)

    #include <stdio.h>

    int main()

    {

    char a[100];

    scanf("%s",a);

    printf("%d",check(a));



}

int check(char a[])

{

    //printf("%s\n",a);

    int i=0;

    for(i=0;i<strlen(a);i++){

        if(a[i]=='H'){

            a[i]='T';

            a[i+1]=a[i+1]=='H'?'T':'H';

            if(check(a)){

                a[i+1]=a[i+1]=='H'?'T':'H';

                if(check(a))a[i]='H';

                else return (i+1);

            }

            else return -(i+1);

        }

    }

    //printf("Lost\n");

    return 0;

}

有人可以帮助我吗?

3 个答案:

答案 0 :(得分:0)

可能是输入字符过多而且输入数组溢出。

您可以尝试更改该行:

char a[100];

将100增加到更大的数字。

答案 1 :(得分:0)

当您输入字符H时,此部分代码将进入无限循环。

for(i=0;i<strlen(a);i++){
    if(a[i]=='H'){  // if passes when input char `H`  
        a[i]='T';   // its changed to `T`
        a[i+1]=a[i+1]=='H'?'T':'H'; // Here a[1] becomes `H`
        if(check(a)) {  // goes back to function call and loops infinitely 
           ...

因此,您需要检查您的算法要求以适应您的代码行为。

答案 2 :(得分:0)

您没有正确撤消您尝试的所有动作。如果您不撤消移动,则永远不会回溯。

此外,您将从check返回用作布尔函数的数字。

这是一个有效的样本。

#include <stdio.h>
#include <string.h>

//#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define FLIP(x) ( ((x)=='H') ? 'T' : 'H' )


bool check(char* a) {
  DEBUG("%s\n",a);

  // Loop over the string.
  for (int i=0; i<strlen(a); i++) {
    // If this coin is a head, try flipping it.
    if (a[i]=='H') {
      // Try flipping just this coin.
      a[i]=FLIP(a[i]);
      // See if it is a win or a loss for the other player.
      if (!check(a)) {
        // A loss for the other player means a win for us!
        // Undo our last move.
        a[i]=FLIP(a[i]);
        return true;
      }
      // A win for the other player.  
      // See if flipping the next coin makes a difference.
      if (i+1 < strlen(a)) {
        a[i+1]=FLIP(a[i+1]);
        // See if it is a win or a loss for the other player.
        if (!check(a)) {
          // A loss for the other player means a win for us!
          // Undo our last two moves.
          a[i]=FLIP(a[i]);
          a[i+1]=FLIP(a[i+1]);
          return true;
        }
        // Still a loss.  Undo this move.
        a[i+1]=FLIP(a[i+1]);
      }
      // Still a loss.  Undo this move.
      a[i]=FLIP(a[i]);
    } // if (a[i]=='H')
  } // for (int i=0; i<strlen(a); i++)

  // Loss.
  return false;
}

int main() {
  char a[100];
  scanf("%s",a);
  if (check(a)) {
    printf("Winner!\n");
  } else {
    printf("Loser!\n");
  }
}