zoukankan      html  css  js  c++  java
  • 算法学习---一个博弈问题

    引用自matrix67的博客。

     
     让我们来玩一个游戏。下面有五行石子,白色的石子都是我的,黑色的石子都是你的。我们轮流拿走一个自己的石子,并且规定如果一个石子被拿走了,它后面的所有石子都要被扔掉。谁先没有拿的了,谁就输了。

    ○●●○●●○●●○
    ●○○●○●●○●
    ○○○○
    ●●●○●●●


    ..比如说,如果你先走的话,你可以把第四行的第三个石子拿走,按规定第四行将会只剩下前面两个石子:

    ○●●○●●○●●○

    ●○○●○●●○●

    ○○○○

    ●●

    现在轮到我走了。我可以拿走第二行倒数第二个石子,于是整个棋局变成了这样:

    ○●●○●●○●●○

    ●○○●○●●

    ○○○○

    ●●

    现在,假如说你拿走了第二行中的第一个石子(于是第二行就没了),那么我就赢定了。我可以拿走第一行中的第一个石子,从而让整个棋局只剩下后面三行:

    ○○○○

    ●●


     

    要求给出一种最合理的走法。


    如果是残局
    ○○○○
    ●● 

    把每个白色石子记作 +1 ,把每个黑色石子记作 -1 。于是 ○○○○ + ●● + ● = 4 – 2 – 1 = 1 ,结果是一个正数(记这个结果为特征值),这就表明该局面下我将必胜,即使此时轮到我先走。

    你会发现上面的说法很有道理 如果棋局是这样

    ○○
    ●●●●
     
    ○○ + ●●●● = 2 – 4 = -2 ,是一个负数,这就意味着不管谁先走,你都能必胜,

    如果是

    ○○
    ●●

    如果我先走你后走,你就赢定了;如果你先走我后走,我就赢定了。因为 和为0。


    所以正确的走法:只需要走特征值最大的就可以了。

    博客原文http://www.matrix67.com/blog/archives/6333

    算法:

    #include <stdio.h>
    #include <stdlib.h>
    
    template <class type>
    void inline Swap(type &a,type &b)
    {
    	type tmp=a;
    	a=b;
    	b=tmp;
    }
    
    
    
    class Chess
    {
    public:
    	Chess()
    	{
    		int i,j;
    		int c[5][10]=
    		{{0,1,1,0,1,1,0,1,1,0},
    		{1,0,0,1,0,1,1,0,1,-1},
    		{0,0,0,0,-1,-1,-1,-1,-1,-1},
    		{1,1,1,0,1,1,1,-1,-1,-1},
    		{1,-1,-1,-1,-1,-1,-1,-1,-1,-1} 	};  
    
    		//1是黑棋 0是白棋
    
    		for(i=0;i<5;i++)
    			for(j=0;j<10;j++)
    				chess[i][j]=c[i][j];
    		rows=5;
    		
    	}
    
    	Chess(Chess &other)
    	{
    		int i,j;
    		for(i=0;i<other.rows;i++)
    		{for(j=0;j<10;j++)	
    			chess[i][j]=other.chess[i][j];
    		}
    		rows=other.rows;
    
    	}
    
    
    	int isWin(int turn) const  //1该黑棋走,0该白棋走
    	{
    		if (rows==0) return 1;
    				
    		int i,j;
    		for(i=0;i<rows;i++)
    		{
    			for(j=0;j<10;j++)
    			{
    				if(chess[i][j]==!turn) return 0;
    			}
    		}
    		return 1;
    
    		
    
    	}
    
    	void takeout(int k,int l)
    	{
    	
    		int i,j,flag=0;
    	
    
    	
    		for(j=l;j<10;j++) chess[k][j]=-1;
    
    		for(j=0;j<10;j++) 
    		{
    			flag=chess[k][j]!=-1;
    			if (flag==1) break;
    				
    		}
    		if(flag==0)
    		{
    				
    			for(i=k;i<rows-1;i++)
    			{
    				for(j=0;j<10;j++)
    				{
    					Swap(chess[i][j],chess[i+1][j]);
    				}
    			}
    
    			rows--;
    		}
    
    		
    	}
    	
    	int CheckInput(int i,int j)
    	{
    
    		if(i<0||i>=rows||j<0||j>=10) 
    		{
    			printf("该棋子不存在!
    ");
    			return 0;
    		}
    		else
    		{
    			if(chess[i][j]==-1) {
    				printf("该棋子不存在!2
    ");
    				return 0;
    			}
    			if(chess[i][j]==0) {
    				printf("您不能选择白棋!
    ");
    				return 0;
    			}
    
    	
    		}
    	return 1;
    
    	}
    
    
    	double EigenValue() const
    	{
    		double value = 0;
    		int i,j;
    		for(i=0;i<rows;i++)
    		{
    			if (chess[i][0] == 0 && chess[i][1] == 0 && chess[i][2] == -1)
    			{
    				value+= 0.5;
    			}
    			else
    			{
    			
    
    				for(j=0;j<10;j++)
    				{
    				
    					switch(chess[i][j])
    					{
    						case 1:value--;break;
    						case 0:value++;break;
    		
    
    					}
    				}
    			}
    
    		}
    		return value;
    
    	}
    
    	void print() const 
    	{
    		int i,j;
    		for(i=0;i<rows;i++)
    		{
    			for(j=0;j<10;j++)
    			{
    				switch(chess[i][j])
    				{
    				case 1:printf("●");break;
    				case 0:printf("○");break;
    		
    
    				}
    			}
    			printf("
    ");
    		}
    
    
    	}
    int chess[5][10];
    int rows;
    
    };
    
    
    
    //AI下棋的程序
    void AIPredict(Chess c,int &AIi,int &AIj)
    {
    
    
    	struct v{
    		int i,j;
    		double value;
    		
    	} value[50];
    	int count=0,i,j;
    	
    	
    	
    	for(i=0;i<c.rows;i++)
    		{
    			for(j=0;j<10;j++)
    			{
    				if(c.chess[i][j]==0)
    				{
    					Chess predict=c;
    					predict.takeout(i,j);
    					value[count].i=i;
    					value[count].j=j;
    					value[count].value=predict.EigenValue();
    					count++;
    				}
    			}
    		}
    
    	v maxvalue=value[0];
    	for(i=1;i<count;i++)
    	{
    		if(value[i].value>maxvalue.value)
    		{
    			maxvalue=value[i];
    		}
    
    	}
    
    	AIi=maxvalue.i;
    	AIj=maxvalue.j;
    
    
    
    }
    
    
    int main()
    {
    	system("color F0");
    	printf("游戏规则:
    下面有五行石子,白色空心○的石子都是我的,黑色实心●的石子都是你的。
    我们轮流拿走一个自己的石子,并且规定如果一个石子被拿走了,
    它后面的所有石子都要被扔掉。谁先没有拿的了,谁就输了。
    
    ");
    	Chess c;
    	c.print();
    	printf("
    
    ");
    	
    	int i,j,turn;
    
    	printf("你想先手还是后手?1为先手,0为后手:");
    	scanf("%d", &turn);
    
    
    	printf("
    ");
    	while(!c.isWin(turn))
    	{
    		
    		if (turn==1) {
    			
    			do{
    			
    				printf("请输入i j表示你要下的位置:(从0开始)");
    				scanf("%d %d",&i,&j);
    				
    			
    			}while(!c.CheckInput(i,j));
    
    				c.takeout(i,j);
    				printf("
    
    ");
    				c.print();
    		
    		}
    		else
    		{
    			AIPredict(c,i,j);
    			printf("电脑下的位置是:<%d,%d>
    ",i,j);
    			c.takeout(i,j);
    			printf("
    
    ");
    			c.print();
    
    		}
    
    		turn = !turn;
    	}
    
    	if(turn)
    	{
    		printf("你赢了!
    ");
    	}
    	else
    	{
    		printf("你输了!
    ");
    	}
    
    
    
    
    
    	system("pause");
    	return 0;
    
    }
    

      

  • 相关阅读:
    (Java实现) 删数问题
    (Java实现) 车站
    (Java实现) 活动选择
    (Java实现) 过河卒
    (Java实现) 美元汇率
    (Java实现) 零件分组
    (Java实现) 图的m着色问题
    (Java实现) 数塔问题
    Java实现 蓝桥杯VIP 算法训练 数的划分
    DirectUI的消息流转
  • 原文地址:https://www.cnblogs.com/xcr1234/p/4550385.html
Copyright © 2011-2022 走看看