博弈

1、取球博弈(1)

 今盒裏有n個小球,A、B兩人輪流從盒中取球。
每個人都可以看到另一個人取了多少個,也可以看到盒中還剩下多少個。
 兩人都很聰明,不會做出錯誤的判斷。 
每個人從盒子中取出的球的數目必須是:1,3,7或者8個。 
輪到某一方取球時不能棄權! A先取球,然後雙方交替取球,直到取完。 
被迫拿到最後一個球的一方爲負方(輸方) 編程確定出在雙方都不判斷失誤的情況下,
對於特定的初始球數,A是否能贏?
#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或O
2. 誰先讓字母組成了“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');
	}
}

發佈了17 篇原創文章 · 獲贊 3 · 訪問量 9251
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章