ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

一道博弈题

2021-08-11 13:33:20  阅读:170  来源: 互联网

标签:prime 博弈 int 笨笨 一道 20005 强强 递推


考场上没想出来,最后讨论时发现精妙之处的一道题


精妙1:

强强和笨笨都足够聪明和自私,那么他们如果能赢,一定走最小步数。

而如果他们输了,一定让另一个人走最多步数

这是解题的其中一个关键


精妙2:

因为两人必定决出胜负,所以每个问题不是输,就是赢

看似是一句废话,其实为最后的递推作了铺垫。

有了这两个精妙之处,就可以解题了


第一步:筛素数,随便你怎么筛

第二步:开始递推

g(i)表示从i到0的回合数(输了)

f(i)表示从i到0的回合数(答案)

为什么要这么记呢?,看下面的递推


若f(i-prime(k))==-1(表示i-prime(k))输了,此时f(i)=min(f(i),g(i-prime(k))+1);

若所有f(i-prime(k))都不等于-1,则g(i)=max(g(i),f(i-prime(k)+1)并且f(i-prime(k)>0

f的递推全由g转来,而g的递推全由f转来。


怎样想明白为什么g要取最大值而f要取最小值?

自己的理解:如果把自己置身于笨笨,则会看不清楚。若把自己置身于游戏中,就会恍然大悟。
g(i)不仅仅时笨笨一人的状态,同时也是强强的状态,若笨笨在f(i+prime)则强强要走g(i)此时强强必输,而强强很聪明,所以就很好理解为什么要取max了。

最后上代码:

#include<bits/stdc++.h>
using namespace std;
int tot,f[20005],p[20005],g[20005],a[20005],n,x;
int main()
{
	for(int i=2;i<=20000;i++)
	{
		if(a[i]==0)tot++,p[tot]=i;
		for(int j=2;j<=20000/i;j++)
		{
			a[i*j]=1;
		}
	}
	a[1]=1;
	g[0]=0;
	g[1]=0;
	memset(f,-1,sizeof(f));
	for(int i=1;i<=20000;i++)
	{
		for(int j=tot;j>=1;j--)
		{
			if(p[j]>i)continue;
			if(f[i-p[j]]==-1)
			{
				if(f[i]==-1)
				{
					f[i]=1e9;
				}
				f[i]=min(f[i],g[i-p[j]]+1);
			}
		}
		if(f[i]==-1)
		{
			for(int j=tot;j>=1;j--)
			{
				if(p[j]>i)continue;
				if(f[i-p[j]]>0)
					g[i]=max(g[i],f[i-p[j]]+1);
			}
		}
	}
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&x);
		printf("%d\n",f[x]);
	}
} 

标签:prime,博弈,int,笨笨,一道,20005,强强,递推
来源: https://www.cnblogs.com/Mistysun/p/15127786.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有