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

A simple stone game

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 174    Accepted Submission(s): 79


Problem Description
After he has learned how to play Nim game, Mike begins to try another stone game which seems much easier.

The game goes like this: Two players start the game with a pile of n stones. They take stones from the pile in turn and every time they take at least one stone. The one who goes first can take at most n-1 stones for his first move. From then on a player can take at most k times as many stones as his opponent has taken last time. For example, if one player take m stones in his turn, then the other player can take at most k × m stones next time. The player who takes the last stone wins the game. Suppose that those two players always take the best moves and never make mistakes, your job is to find out who will definitely win the game.
 

Input
The first line contains a integer t, indicating that there are t test cases following.(t<=20).

Each test case is a line consisting of two integer n and k.(2<=n<=10^8,1<=k<=10^5).
 

Output
For each test case, output one line starting with “Case N: ”, N is the case number. And then, if the first player can ensure a winning, print the minimum number of stones he should take in his first turn. Otherwise, print "lose". Please note that there is a blank following the colon.
 

Sample Inpu
   
   
   
   
5 16 1 11 1 32 2 34 2 19 3
 

Sample Output
   
   
   
   
Case 1: lose Case 2: 1 Case 3: 3 Case 4: lose Case 5: 4


题目大意:给定整数n和k。有n个石头,两个人来取。先手可以取1~n-1个。接下来每次最多能取上一个人取的k倍,即1~k*n; 求先手是否一定能赢!能赢输出第一次最少取几个。否则输出lose。

PS:我想这种变态题目的原因: 今天早上比赛时没人做出来,到了晚上貌似还是没人会,不幸抽签中奖,由我讲解这题。。。。O M G!! 参照网上代码,找了好久的规律!最后时刻想出来了。可惜还是准备不充分,没能表达清楚。。。


思想:找规律  然后  博弈,还有点dp的思想。。。


以下是代码以及解答思路:附上涂鸦一副

POJ3922 、HDU2486、HDU2580坑爹的博弈,一般人想五个小时也想不出啊!!_第1张图片


#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 1000
using 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] 
			else
				maxok[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,29
maxok=1,2,3,5,7,10,14,20
*/ 


你可能感兴趣的:(c,Integer,each,output)