zoukankan      html  css  js  c++  java
  • 第二届蓝桥杯省赛---取球游戏

    取球游戏

    今盒子里有n个小球,A、B两人轮流从盒中取球,每个人都可以看到另一个人取了多少个,也可以看到盒中还剩下多少个,并且两人都很聪明,不会做出错误的判断。
    我们约定:
    每个人从盒子中取出的球的数目必须是:1,3,7或者8个。
    轮到某一方取球时不能弃权!
    A先取球,然后双方交替取球,直到取完。
    被迫拿到最后一个球的一方为负方(输方)
    请编程确定出在双方都不判断失误的情况下,对于特定的初始球数,A是否能赢?
    程序运行时,从标准输入获得数据,其格式如下:
    先是一个整数n(n<100),表示接下来有n个整数。然后是n个整数,每个占一行(整数<10000),表示初始球数。
    程序则输出n行,表示A的输赢情况(输为0,赢为1)。
    例如,用户输入:
    4
    1
    2
    10
    18

    则程序应该输出:
    0
    1
    1
    0

    思路一:零和博弈,每个人都按照最优策略出牌,递归就可以解决,但是数据比较大,采用记忆化递归

    f(局面 x) ---> 胜负   

    边界条件处理 

    for(对我所有可能的走法)

         试着走一步 -----> 局面y 

          胜负 t = f(y);    

       if(t==负) return 胜    局面  

      return 负 

    }

    也就是说,让A尝试他走哪一步不会输,他走出一步后,局面发生改变,由对手去下剩下的局面,通过对手的输赢来判断自己的输赢。。。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 
     7 const int maxn = 1e4+10;
     8 int a[maxn];/*a的记忆化体系建立起来之后只有1,-1*/
     9 
    10 //记忆化递归
    11 bool f(int x){
    12     /*递归边界*/
    13     if(x==0) return true;
    14     if(a[x]!=0){
    15         if(a[x]==1) return true; 
    16         else{
    17             return false;
    18         }
    19     }
    20     int flag = 0;
    21     /*  对A来说,如果球数大于1,可以先尝试去拿一个,
    22         如果对方取一个之后对方输了,说明A赢了返回true,
    23         接下来类似,,博弈论。。。
    24     */
    25     if(x>1&&f(x-1)==false) flag=1;
    26     if(x>3&&f(x-3)==false) flag=1;
    27     if(x>7&&f(x-7)==false) flag=1;
    28     if(x>8&&f(x-8)==false) flag=1;
    29 
    30     if(flag){
    31         a[x]=1;
    32         return true;
    33     }
    34     else{
    35         a[x]=-1;
    36         return false;
    37     }
    38 }
    39 
    40 int main(){
    41     int n;
    42     cin>>n;
    43     while(n--){
    44         int d;
    45         cin>>d;
    46         if(f(d)){
    47             cout<<1<<endl;
    48         }
    49         else{
    50             cout<<0<<endl;
    51         }
    52     }
    53 
    54     return 0;
    55 }

     思路二:由于题目的要求,两个人取球,其中每人每一次必取 1, 3, 7, 8 其中的一个数量的球,并且最后一个球被取到的人输,因此得出以下表格:

    因此对于A君先取球,判断A君的游戏情况,可以把“我先拿胜利”的情况均存在r[]数组中并赋值为1,否则r[]数组中其他值赋值为0,即可。

    表格的具体构造过程如下:初始值:int a[maxn]={-1,0,1,0,1,0,1,0,1};       -1表示0个球的情况不存在,存了8个球进去了下标从0开始的

    然后 i = 9;判断 ( a[i-8]==1&& a[i-3]==1&& a[i-7]==1 && a[i-1]==1 ),
    如果成立,说明无论A走哪一步,对方都可以胜利,则a[i] = 0,否则,a[i]=1;

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 
     5 const int maxn = 1e4+10;
     6 int a[maxn];
     7 void init(int a[]){
     8     a[0] = -1;
     9     for( int i=2; i<=8; i+=2){
    10         a[i]=1;
    11     }
    12     for( int i=9; i<=maxn; i++ ){
    13         if(a[i-1]==1&&a[i-3]==1&&a[i-7]==1&&a[i-8]==1){//无论A走哪一步,都是对方赢,则a[i]=0,即i个球A先拿时,A必输
    14             a[i]=0;
    15         }
    16         else{
    17             a[i]=1;
    18         }
    19     }
    20 }
    21 
    22 int main(){
    23     init(a);
    24     int n;
    25     cin>>n;
    26     while(n--){
    27         int d;
    28         cin>>d;
    29         if(a[d]){
    30             cout<<1<<endl;
    31         }
    32         else{
    33             cout<<0<<endl;
    34         }
    35     }
    36     return 0;
    37 }
    有些目标看似很遥远,但只要付出足够多的努力,这一切总有可能实现!
  • 相关阅读:
    数字基本数据类型范围比较
    java中float和double的区别
    ASP.NET中javascript与c#互相访问
    Javascript技术之详尽解析event对象
    Java基础-Java中的Calendar和Date类
    逻辑运算符
    JS获取当前时间
    几秒后刷新页面
    【LiteOS】LiteOS任务篇源码分析删除任务函数
    POJ 2385 Apple Catching (DP)
  • 原文地址:https://www.cnblogs.com/Bravewtz/p/10424642.html
Copyright © 2011-2022 走看看