POJ3922 、HDU2486、HDU2580坑爹的博弈,一般人想五个小时也想不出啊!!
转载请注明出处:http://blog.csdn.net/cxb569262726/article/details/7841521
题目链接:
http://poj.org/problem?id=3922
http://acm.hdu.edu.cn/showproblem.php?pid=2486
http://acm.hdu.edu.cn/showproblem.php?pid=2580
516 111 132 234 219 3
Case 1: loseCase 2: 1Case 3: 3Case 4: loseCase 5: 4
题目大意:给定整数n和k。有n个石头,两个人来取。先手可以取1~n-1个。接下来每次最多能取上一个人取的k倍,即1~k*n; 求先手是否一定能赢!能赢输出第一次最少取几个。否则输出lose。
PS:我想这种变态题目的原因: 今天早上比赛时没人做出来,到了晚上貌似还是没人会,不幸抽签中奖,由我讲解这题。。。。O M G!! 参照网上代码,找了好久的规律!最后时刻想出来了。可惜还是准备不充分,没能表达清楚。。。
思想:找规律 然后 博弈,还有点dp的思想。。。
以下是代码以及解答思路:附上涂鸦一副
#include<iostream>#include<algorithm>#include<stdio.h>#include<stdlib.h>#include<string.h>#include<queue>#include<math.h>#include<set>#include<vector>#define MAXN 15#define INF 1000using namespace std;int no[2000000],maxok[2000000];//no储存的是lose的数。 maxok【i】存的是在i之前能组成的最大的数; int main(){int i,j,n,m,k,t,c,ca=0;for(scanf("%d",&t);t--;){ca++;scanf("%d%d",&n,&k);if(n<=k+1)//n<=k+1时一定是输; {printf("Case %d: lose\n",ca);continue;}int x=0,y=0;no[0]=maxok[0]=1;while(no[x]<n){x++;no[x]=maxok[x-1]+1;//在x之前,最大的能符合的数是maxok【x-1】、加1后就不符合。 while(no[y+1]*k<no[x])//找小于no[x]的最大数:例子k=3时有15得到4 y++;if(no[y]*k<no[x])//前面得到的数可能不符合条件 maxok[x]=no[x]+maxok[y];//如果符合直接得no[x]+maxok[y];例子中推得15+maxok[3] elsemaxok[x]=no[x];//否则能组成最大的数为本身。 }if(no[x]==n)//刚好组成n 说明这个数属于no数组。即不能由符合条件的数组成,lose! {printf("Case %d: lose\n",ca);continue;}int ans;while(n){if(n>=no[x])//不断的减去最大的数,剩下的最小的数就是了。 {ans=no[x];n-=no[x];}x--;}printf("Case %d: %d\n",ca,ans);} return 0;}/*k=3时: no={1,2,3,4,6,8,11,15,21,29maxok=1,2,3,5,7,10,14,20*/