1、取球博弈(1)
每個人都可以看到另一個人取了多少個,也可以看到盒中還剩下多少個。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int f(int a){
if(a == 0) return 0;
if(a >= 1 && f(a - 1) == 0) return 1;
if(a >= 3 && f(a - 3) == 0) return 1;
if(a >= 7 && f(a - 7) == 0) return 1;
if(a >= 8 && f(a - 8) == 0) return 1;
return 0;
}
int main(){
for(int i = 1; i < 50; i++){
printf("%2d: %d\n", i, f(i));
}
}
2、取球博弈(2)兩個人玩取球的遊戲。
一共有N個球,每人輪流取球,每次可取集合{n1,n2,n3}中的任何一個數目。
如果無法繼續取球,則遊戲結束。
此時,持有奇數個球的一方獲勝。
如果兩人都是奇數,則爲平局。
假設雙方都採用最聰明的取法,
第一個取球的人一定能贏嗎?
試編程解決這個問題。
輸入格式:
第一行3個正整數n1 n2 n3,空格分開,表示每次可取的數目 (0<n1,n2,n3<100)
第二行5個正整數x1 x2 ... x5,空格分開,表示5局的初始球數(0<xi<1000)
輸出格式:
一行5個字符,空格分開。分別表示每局先取球的人能否獲勝。
能獲勝則輸出+,
次之,如有辦法逼平對手,輸出0,
無論如何都會輸,則輸出-
例如,輸入:
1 2 3
1 2 3 4 5
程序應該輸出:
+ 0 + 0 -
再例如,輸入:
1 4 5
10 11 12 13 15
程序應該輸出:
0 - 0 + +
2 3 5
7 8 9 10 11
程序應該輸出:
+ 0 0 0 0
資源約定:
峯值內存消耗(含虛擬機) < 256M
CPU消耗 < 3000ms
請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多餘內容。
所有代碼放在同一個源文件中,調試通過後,拷貝提交該源碼。
注意:不要使用package語句。不要使用jdk1.7及以上版本的特性。
注意:主類的名字必須是:Main,否則按無效代碼處理。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//f 標誌是哪個人
//c 標誌正在改寫的對象 f函數和 f1, f2等價
int f(int * a, int b, int c, int d){
int flag = 1;
for(int i = 0; i< 3; i++){
if(a[i] <= b){
flag = 0;
break;
}
}
if(b == 0 || flag == 1){
if(c % 2 == 0 && d % 2 == 0){
return 0;
}
else if(c % 2 == 1 && d % 2 == 1){
return 0;
}
else if(c % 2 == 1 && d % 2 == 0){
return 1;
}
else if(c % 2 == 0 && d % 2 == 1){
return -1;
}
}
int tag = -1;
for(int i = 0; i < 3; i++){
if(b >= a[i] && f(a, b - a[i], d, c + a[i]) == -1){
return 1;
}
if(b >= a[i] && f(a, b - a[i], d, c + a[i]) == 0){
tag = 0;
}
}
return tag;
}
int f2(int * a, int b, int c, int d);
int f1(int * a, int b, int c, int d){
int flag = 1;
for(int i = 0; i< 3; i++){
if(a[i] <= b){
flag = 0;
break;
}
}
if(b == 0 || flag == 1){
if(c % 2 == 0 && d % 2 == 0){
return 0;
}
else if(c % 2 == 1 && d % 2 == 1){
return 0;
}
else if(c % 2 == 1 && d % 2 == 0){
return 1;
}
else if(c % 2 == 0 && d % 2 == 1){
return -1;
}
}
else{
int tag = -1;
for(int i = 0; i < 3; i++){
if(b >= a[i] && f2(a, b - a[i], c + a[i], d) == -1){
return 1;
}
if(b >= a[i] && f2(a, b - a[i], c + a[i], d) == 0){
tag = 0;
}
}
return tag;
}
}
int f2(int * a, int b, int c, int d){
int flag = 1;
for(int i = 0; i< 3; i++){
if(a[i] <= b){
flag = 0;
break;
}
}
if(b == 0 || flag == 1){
if(c % 2 == 0 && d % 2 == 0){
return 0;
}
else if(c % 2 == 1 && d % 2 == 1){
return 0;
}
else if(c % 2 == 1 && d % 2 == 0){
return -1;
}
else if(c % 2 == 0 && d % 2 == 1){
return 1;
}
}
else{
int tag = -1;
for(int i = 0; i < 3; i++){
if(b >= a[i] && f1(a, b - a[i], c, d + a[i]) == -1){
return 1;
}
if(b >= a[i] && f1(a, b - a[i], c, d + a[i]) == 0){
tag = 0;
}
}
return tag;
}
}
int main(){
int a[3];
int b[5];
for(int i = 0; i < 3; i++){
scanf("%d", &a[i]);
}
for(int i = 0; i < 5; i++){
scanf("%d", &b[i]);
}
for(int i = 0; i < 5; i++){
int c = b[i];
// printf("c %d\n", c);
int t = f1(a, c, 0, 0);
if(t == 1){
printf("+");
}
else if(t == 0){
printf("0");
}
else if(t == -1){
printf("-");
}
if(i != 4){
printf(" ");
}
}
}
3、填字母遊戲
K大師在紙上畫了一行n個格子,要小明和他交替往其中填入字母。
1. 輪到某人填的時候,只能在某個空格中填入L或O2. 誰先讓字母組成了“LOL”的字樣,誰獲勝。
3. 如果所有格子都填滿了,仍無法組成LOL,則平局。
小明試驗了幾次都輸了,他很慚愧,希望你能用計算機幫他解開這個謎。
本題的輸入格式爲:
第一行,數字n(n<10),表示下面有n個初始局面。
接下來,n行,每行一個串,表示開始的局面。
比如:“******”, 表示有6個空格。“L****”, 表示左邊是一個字母L,它的右邊是4個空格。
要求輸出n個數字,表示對每個局面,如果小明先填,當K大師總是用最強着法的時候,小明的最好結果。
1 表示能贏
-1 表示必輸
0 表示可以逼平
例如,
輸入:
4
***
L**L
L**L***L
L*****L
則程序應該輸出:
0
-1
1
1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int f1(char * c){
char * a = (char *)malloc(strlen(c) + 1);
memset(a, 0, strlen(c) + 1);
strcpy(a, c);
if (strstr(a, "LOL") != NULL){
return -1;
}
if (strchr(a, '*') == NULL){
return 0;
}
int b = -1;
for (int i = 0; i < strlen(a); i++){
if(a[i] == '*'){
a[i] = 'L';
switch(f1(a)){
case 0:
b = 0;
break;
case -1:
return 1;
}
a[i] = 'O';
switch(f1(a)){
case 0:
b = 0;
break;
case -1:
return 1;
}
a[i] = '*';
}
}
return b;
}
int f(char * a){
if (strstr(a, "LOL") != NULL){
return -1;
}
if (strchr(a, '*') == NULL){
return 0;
}
int b = -1;
for (int i = 0; i < strlen(a); i++){
if(a[i] == '*'){
a[i] = 'L';
switch(f(a)){
case 0:
b = 0;
a[i] = '*';
break;
case -1:
a[i] = '*';
return 1;
default:
a[i] = '*';
}
a[i] = 'O';
switch(f(a)){
case 0:
b = 0;
a[i] = '*';
break;
case -1:
a[i] = '*';
return 1;
default:
a[i] = '*';
}
}
}
return b;
}
int main(){
char a[] = "L*****L";
printf("%d\n", f(a));
puts(a);
// f1("L**L");
// f1("L**L***L");
// f1("L*****L");
}
switch 要使用default復原公共串,或者另外開一個空間存放要使用的串
4、高僧鬥法
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int f(int * n, int len){
int a = 0;
for (int i=0; i<len-1; i+=2){
a ^= n[i+1] - n[i] - 1;
}
if(a != 0){
return 1;
}
return 0;
}
void f1(int * a, int len){
for (int i = 0; i < len - 1; i++){
for (int j = a[i] + 1; j < a[i + 1]; j++){
int b = a[i];
a[i] = j;
if (f(a, len) == 0){
printf("%d %d\n", b, j);
a[i] = b;
return ;
}
a[i] = b;
}
}
printf("-1\n");
}
int main(){
int x[] = { 1, 5, 9 };
f1(x,3);
int y[] = { 1, 5, 8, 10 };
f1(y,4);
int z[] = { 1, 4, 8, 12, 16, 19, 28, 33, 35, 36, 40, 45, 52, 66, 67, 68, 69, 77, 85, 99, 102, 134, 155, 211, 214, 216, 355, 376, 400, 412 };
f1(z,30);
}
5、古代賭局
俗話說:十賭九輸。因爲大多數賭局的背後都藏有陰謀。
不過也不盡然,有些賭局背後藏有的是:“陽謀”。
有一種賭局是這樣的:桌子上放六個匣子,編號是1至6。
多位參與者(以下稱玩家)可以把任意數量的錢押在某個編號的匣子上。
所有玩家都下注後,莊家同時擲出3個骰子(骰子上的數字都是1至6)。
輸贏規則如下:
1.若只有1個骰子上的數字與玩家所押注的匣子號相同,則玩家拿回自己的押注,莊家按他押注的數目賠付(即1比1的賠率)。
2.若2個骰子上的數字與玩家所押注的匣子號相同,則玩家拿回自己的押注,莊家按他押注的數目的2倍賠付(即1比2的賠率)。
3.若3個骰子上的數字都與玩家押注的匣子號相同,則玩家拿回自己的押注,莊家按他押注的數目的10倍賠付(即1比10的賠率)。
乍一看起來,好像規則對玩家有利,莊家吃虧。但經過大量實戰,會發現局面很難說,於是懷疑是否莊家做了手腳,莊家則十分爽快地說:可以由玩家提供骰子,甚至也可以由玩家來投擲骰子。
你的任務是:通過編程模擬該過程。模擬50萬次,假定只有1個玩家,他每次的押注都是1元錢,其押注的匣子號是隨機的。再假定莊家有足夠的資金用於賠付。最後計算出莊家的盈率(莊家盈利金額/押注總金額)。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
void f(int * a){
for(int i = 0; i < 3; i++){
a[i] = (int)(rand()/(RAND_MAX + 0.0) * 6 + 1);
}
}
int f1(int * a){
int b = (int)(rand()/(RAND_MAX + 0.0) * 6 + 1);
int c = 0;
f(a);
for(int i = 0; i < 3; i++){
if(a[i] == b){
c++;
}
}
switch(c){
case 0: return 1;
case 1: return -1;
case 2: return -2;
case 3: return -10;
}
}
int main(){
srand(time(NULL));
int a[3];
double b = 0;
for(int i = 0; i < 500 * 1000; i++){
int c = f1(a);
// printf("%d %d\n", i, c);
b += c;
}
printf("%f\n", b);
printf("%f", b / (500 * 1000));
}
6、火柴遊戲
1,在3x4的格子中,遊戲的雙方輪流放置火柴棒。
其規則是:
1. 不能放置在已經放置了火柴棒的地方(即只能在空格中放置)。
2. 火柴棒的方向只能是豎直或水平放置。
3. 火柴棒不能與其它格子中的火柴“連通”。
所謂連通是指兩根火柴棒可以連成一條直線,且中間沒有其它不同方向的火柴“阻攔”。
例如:
圖1所示的局面下,可以在C2位置豎直放置(爲了方便描述格子位置,圖中左、下都添加了標記),
但不能水平放置,因爲會與A2連通。
同樣道理,B2,B3,D2此時兩種方向都不可以放置。
但如果C2豎直放置後,D2就可以水平放置了,因爲不再會與A2連通(受到了C2的阻擋)。
4. 遊戲雙方輪流放置火柴,不可以棄權,也不可以放多根。
如某一方無法繼續放置,則該方爲負(輸的一方)。
遊戲開始時可能已經放置了多根火柴。
你的任務是:編寫程序,讀入初始狀態,計算出對自己最有利的放置方法並輸出放置後的局面。
圖1的局面表示爲:
00-1
-000
0100
即用“0”表示空閒位置,用“1”表示豎直放置,用“-”表示水平放置。
解法不唯一,找到任意解法即可。
例如,局面:
0111
-000
-000
的解:
-111
-000
-000
再例如,局面:
1111
----
0010
的解:
1111
----
0110
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int f1(char (*a)[5]){
int b[3 + 4];
memset(b, 0, 4 * 7);
for(int i = 0; i < 3; i++){
for(int j = 0; j < 4; j++){
if(a[i][j] == '1'){
b[i] += 1;
}
if(a[i][j] == '-'){
b[i] += -1;
}
}
}
for(int i = 0; i < 3; i++){
for(int j = 0; j < 4; j++){
if(a[i][j] == '1'){
b[j + 3] += 1;
}
if(a[i][j] == '-'){
b[j + 3] += -1;
}
}
}
// printf("b : ");
// for(int i = 0; i < 7; i++){
// printf("%d ", b[i]);
// }
if(b[0] < -1 || b[1] < -1 || b[2] < -1){
return 0;
}
if(b[3] > 1 || b[4] > 1 || b[5] > 1 || b[6] > 1){
return 0;
}
return 1;
}
int f(char (* a)[5]){
int b = f1(a);
// printf("\nf1(a): %d\n", b);
if(b == 0){
return 1;
}
int tag = 0;
for(int i = 0; i < 3; i++){
for(int j = 0; j < 4; j++){
if(a[i][j] == '0'){
a[i][j] = '1';
if(f(a) == 0){
return 1;
}
a[i][j] = '-';
if(f(a) == 0){
return 1;
}
a[i][j] = '0';
}
}
}
return 0;
}
int main(){
char a[3][5];
char b[3][5];
memset(a, 0, 15);
gets(a[0]);
gets(a[1]);
gets(a[2]);
memcpy(b, a, 15);
printf("%d \n", f(a));
int c = 0;
if (memcmp(a,b, 15) == 0){
for (int i = 0; i < 3; i++){
for(int j = 0; j < 4; j++){
if(a[i][j] == '0'){
a[i][j] = '1';
c = 1;
break;
}
}
if(c == 1){
break;
}
}
}
for (int i=0; i<3; i++){
for(int j=0; j<4; j++){
printf("%c", a[i][j]);
}
putchar('\n');
}
}