[题目]
甲乙两人从24枚棋子中轮流取子,甲先取,规定每次所取的枚数不能多于上一个人所取的枚数,也不可不取。
(1)甲第一次取多少枚才能保证甲取得最后一枚,当然,他也不能第一次就把所有棋子都取走。
(2)讨论棋子总数N(一定是偶数)从6到30的各种情况。讨论内容包括:
对各个N,是否存在一个小于N的枚数M,甲第一次取M枚后就能保证甲如果策略正确,一定能取到最后一枚棋子。
[C#]
public const int N = 24 ;
public static int [] L = new int [N + 1 ];
public static void Main(String[] args)
{
for ( int i = N - 1 ; i > 0 ; i -- )
{
Console.WriteLine( " First Time get: {0} " , i);
L[ 0 ] = i;
Solve( 1 , N - i , i);
Console.WriteLine();
}
Console.ReadLine();
}
public static void Solve( int count, int leave, int num)
{
int i,j;
if (leave == 1 && count % 2 == 0 && count > 1 )
{
L[count] = 1 ;
for (i = 0 ; i <= count; i ++ )
Console.Write( " {0,4} " , L[i]);
Console.Write( " " );
return ;
}
if (leave < 0 )
return ;
// 每次所取的枚数不能多于(也就是<=)上一个人所取的枚数
// 如果是:每次所取的枚数不能大于等于上一个人所取的枚数
// 则应该改为:for (j = num - 1; j > 1; j--)
for (j = num; j > 0 ; j -- )
// for (j = num - 1; j > 1; j--)
{
L[count] = j;
Solve(count + 1 , leave - j , j);
}
}
[C++]
/**/
/*
甲只要保证第一次取完后留给乙的棋子数是的n次方,且大于所取走的棋子数就必胜
因此,如果开始的棋子数是的n次方,则甲无必胜方法
下面的程序演示了甲的策略,(程序包含了出错处理,所以比较长)
*/
#include < stdlib.h >
#include < iostream >
using namespace std;
#define MAX 100000
int num( int n, int k = 0 );
int main()
... {
int n,k,m;
cout<<"请输入不大于"<<MAX<<"的正整数,输入退出"<<endl;
while(cin>>n&&(n>MAX||n<0))
cout<<"请重新输入"<<endl;
if(n==0)
goto END;
m=num(n);
if(m<0)
goto END;
n-=m;
while(n!=0)
...{
cout<<"我取走"<<m<<" 剩余:"<<n<<endl<<"请问你取走多少个?"<<endl;
while(cin>>k&&(k>m||k<0||k>n))
cout<<"请重新输入"<<endl;
if(k==0)
goto END;
n-=k;
cout<<"你取走"<<k<<" 剩余:"<<n<<endl;
if(n==0)
...{
cout<<"你胜利了!"<<endl;
goto END;
}
m=num(n,k);
if(m<0)
goto END;
n-=m;
}
cout<<"我取走"<<m<<" 剩余:"<<n<<endl;
cout<<"你输了"<<endl;
END:system("pause");
return 0;
}
int num( int n, int k)
... {
if(n<=k)
return n;
int i,t=1;
while(t<=n)
...{
t*=2;
}
t/=2;
if(t==n)
...{
if(k==0)
cout<<"非必胜"<<endl;
t=n/2+2;
}
else if(k==0)
cout<<"必胜"<<endl;
t=n-t;
if(t>k&&k!=0)
...{
t=1;
while(t<=k&&n%t==0)
t*=2;
t/=2;
}
if(t<1||(k!=0&&t>k)||t>n)
...{
cout<<"Error:"<<endl<<n<<" "<<k<<" "<<t<<endl;
return -1;
}
return t;
}
甲只要保证第一次取完后留给乙的棋子数是的n次方,且大于所取走的棋子数就必胜
因此,如果开始的棋子数是的n次方,则甲无必胜方法
下面的程序演示了甲的策略,(程序包含了出错处理,所以比较长)
*/
#include < stdlib.h >
#include < iostream >
using namespace std;
#define MAX 100000
int num( int n, int k = 0 );
int main()
... {
int n,k,m;
cout<<"请输入不大于"<<MAX<<"的正整数,输入退出"<<endl;
while(cin>>n&&(n>MAX||n<0))
cout<<"请重新输入"<<endl;
if(n==0)
goto END;
m=num(n);
if(m<0)
goto END;
n-=m;
while(n!=0)
...{
cout<<"我取走"<<m<<" 剩余:"<<n<<endl<<"请问你取走多少个?"<<endl;
while(cin>>k&&(k>m||k<0||k>n))
cout<<"请重新输入"<<endl;
if(k==0)
goto END;
n-=k;
cout<<"你取走"<<k<<" 剩余:"<<n<<endl;
if(n==0)
...{
cout<<"你胜利了!"<<endl;
goto END;
}
m=num(n,k);
if(m<0)
goto END;
n-=m;
}
cout<<"我取走"<<m<<" 剩余:"<<n<<endl;
cout<<"你输了"<<endl;
END:system("pause");
return 0;
}
int num( int n, int k)
... {
if(n<=k)
return n;
int i,t=1;
while(t<=n)
...{
t*=2;
}
t/=2;
if(t==n)
...{
if(k==0)
cout<<"非必胜"<<endl;
t=n/2+2;
}
else if(k==0)
cout<<"必胜"<<endl;
t=n-t;
if(t>k&&k!=0)
...{
t=1;
while(t<=k&&n%t==0)
t*=2;
t/=2;
}
if(t<1||(k!=0&&t>k)||t>n)
...{
cout<<"Error:"<<endl<<n<<" "<<k<<" "<<t<<endl;
return -1;
}
return t;
}