风云剑 发表于 2008-7-1 16:03:16

一个老题,扑克博弈

蛮有趣的博弈问题A,B两人玩一个游戏,每位参加者发18张牌:三张6点,三张5点,三张4点,三张3点,三张2点,三张1点.
他们轮流出牌,A先出一张,B再出一张,每轮不能不出牌.
谁先出的牌使得桌子上的牌的全部点数之和等于50谁就算赢了,
但若那张牌使全部点数之和超过了50,他就算输了.问A和B谁有必胜策略?

zgg___ 发表于 2008-7-1 17:21:18

倒想起了原来编递归函数来算阶乘。

gxqcn 发表于 2008-7-2 07:47:32

A先出1点,以后看B出x点,则自己出(7-x)点,这样使桌面上的点数总和保持为(7k+1)型,可拿到50的情形。

B看出了苗头,并利用A手头1点数目不足的弱点,最后三轮中连出6点,让A无法形成上述策略而告输。

抛砖引玉。具体怎样设计策略而稳赢,还没想好。

无心人 发表于 2008-7-2 08:29:12

那显然A的策略是必输策略阿
呵呵

mathe 发表于 2008-7-2 08:54:41

可以用程序解决吗?用程序复杂度不高:lol

mathe 发表于 2008-7-2 09:31:37

有简单的方法吗?计算机说只要先手先出3,4,5或6都可以赢

无心人 发表于 2008-7-2 10:26:18

:b:

能不能出示你的程序
另外,这种策略类的游戏
能不能不用C/C++程序
Prolog/Lisp/Haskell/SML/Python等都可以
唯独不要用C/C++,呵呵

mathe 发表于 2008-7-2 10:30:51

习惯用C/C++了,其它语言基本不会用了。
#include <stdio.h>
#define LIMIT (1<<24)
int states;
#define FAIL -1
#define SUCC -2
void gen(int left){
    int first_u=left&((1<<12)-1);
    int second_u=left>>12;
    int cfirst,csecond;
    int i,sum;
    cfirst=csecond=0,sum=0;
    for(i=0;i<6;i++){
      int c1=(first_u>>(2*i))&3;
      int c2=(second_u>>(2*i))&3;
      cfirst+=c1;
      csecond+=c2;
      sum+=(c1+c2)*(i+1);
    }
    sum=126-sum;
    if(sum>50){
      states=FAIL;
    }else if(sum==50){
      states=SUCC;
    }else{
      int s,j;
      for(i=0;i<6;i++){
            s=(first_u>>(2*i))&3;
      }
      for(i=0;i<6;i++){
            int new_u=first_u;
            int reach;
            if(s>0){
                new_u-=1<<(2*i);
            }
            reach=second_u|(new_u<<12);
            if(states==SUCC)
                break;
      }
      if(i<6){
            states=FAIL;
      }else{
            states=SUCC;
      }
    }
}

void output_states(int x);
int next_state(int x)
{
    int first_u=x&((1<<12)-1);
    int second_u=x>>12;
    int i,s;
    for(i=0;i<6;i++){
      s=(first_u>>(2*i))&3;
    }
    int reach=-1;
    for(i=0;i<6;i++){
      int new_u=first_u;
      if(s>0){
            new_u-=1<<(2*i);
            reach=second_u|(new_u<<12);
            if(states==SUCC){
                output_states(reach);
            }
      }
    }
    return reach;
}

void output_states(int x)
{
    printf("State %06x:",x);
    if(states==SUCC){
      printf("F");
    }else{
      printf("S");
    }
    printf("\n");
}

int main()
{
    int i;
    for(i=0;i<LIMIT;i++){
      gen(i);
    }
    output_states(LIMIT-1);
    printf("next states:\n");
    next_state(LIMIT-1);
    return 0;
}

gxqcn 发表于 2008-7-2 10:36:15

原帖由 mathe 于 2008-7-2 09:31 发表 http://bbs.emath.ac.cn/images/common/back.gif
有简单的方法吗?计算机说只要先手先出3,4,5或6都可以赢

可否用文字具体叙述之后的出牌策略?:Q:

mathe 发表于 2008-7-2 10:38:21

程序用一个24比特的整数表示牌局中一个状态,
低12比特代表接下去出牌的人手中牌的状态,高12比特代表另外一个人手中牌的状态。
其中12比特可以看成6个两比特的数据,分别代表持有1,2,3,...,6的数目(0~3张)
然后一次计算各个局面是先手胜还是先手负,结果SUCC表示先手负(无论怎么出牌都会达到FAIL局面),FAIL表示先手胜局面(存在一种出牌方案留下SUCC的局面)
页: [1] 2 3 4
查看完整版本: 一个老题,扑克博弈