小花梨的取石子游戏——java


小花梨的取石子游戏


Problem D、小花梨的取石子游戏
时间限制:1000ms 空间限制:512MB
Description
小花梨有?堆石子,第?堆石子数量为??,?堆石子顺时针编号为1 − ?(如图)。
游戏将进行?轮,每轮游戏单独进行,互不干扰,每轮初始时第?堆石子数目为??。
第?轮从编号为?的那堆石子为起点,顺时针来取石子。两人轮流取石子,不可不取,最少取
一个石子,最多把当前这一堆取完,只有取完一堆后才走到下一堆石子。走完一圈后石子都
被取完,不能取石子的人就失败。假设两人以最优策略进行取石子操作,请分别输出?轮游
戏是先手胜还是后手胜。
Input
第一行为正整数?,表示石子的堆数 (1 ≤ ? ≤ 100000)
第二行输入?个正整数表示每一堆的石子数目??(1 ≤ ?? ≤ 109
)
Output
输出?行,第?行表示第?轮游戏的结果。如果先手胜则输出"?????",后手胜输出"??????"。
Example
Sample Input Sample Output
3
2 1 3
First
Second
First
2
2 2
First
First
Note
样例1:
游戏进行3轮
第1轮游戏石子堆下标的顺序为1 2 3,此时石子数目按顺序为2 1 3,先手胜
第2轮游戏石子堆下标的顺序为2 3 1,此时石子数目按顺序为1 3 2,后手胜
第3轮游戏石子堆下标的顺序为3 1 2,此时石子数目按顺序为3 2 1,先手胜

接下来先说一下我对这道题的看法:
当看到这道题的时候我发现它是一个博弈论;于是我便开始拿着我的板子判断它是属于尼姆博弈,巴什博弈和威佐夫博弈中的哪一种,结果发现,哪一种也不是,所以我认为它是一道思维题;
不断在WA中探索正确的道路,终于被我找到了,但可能是由于复杂度太高,导致超时,还好最后改进了一下,过了。
在这道题中,一共wa了貌似是19次,很悲,希望在比赛的过程中一定要细心一点,不要看着接过去改程序了,考虑要全面一点;
接下来说一下这一题的算法,由于本人表达能力不好,又与题解考虑得近乎一样,就直接用题解了,原谅;

  1. 现在只考虑每一轮游戏;

  2. 一堆的时候是必胜态;

  3. 多堆的时候:
    起点数目大于1,是必胜态
    因为可以取完或者取得只剩下一个,这两种状态的胜负一定不同,也就是说一定可以到达必败状态,所以此时为必胜态;

    起点数目等于1,和下一点的状态相反;(我这这里就主要是判断1的个数了);
    运用到的方法主要就是两次遍历数组,一次从前交往后,一次从后往前,

以下附上我的ac代码:

package 登;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Arrays;

public class D_1 {
	static int n;
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		
		BufferedReader sc=new BufferedReader(new InputStreamReader(System.in));
		PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
		n=Integer.parseInt(sc.readLine());
		String s=sc.readLine();
		String[] ss=s.split(" ");
		int[] ch=new int[n];
		int[] test=new int[n];
		for(int i=0;i<n;i++) {
			ch[i]=Integer.parseInt(ss[i]);
			if(ch[i]!=1) {
				test[i]=0;
			}
			else {
				test[i]=1;
			}
		}
		if(n==1) {
			System.out.println("First");
			return;
		}
		for(int i=(n-1);i>0;i--) {
			if(ch[i-1]==1) {
				if(ch[i]==1) {
					test[i-1]=test[i]+1;
				}else {
					test[i-1]=1;
				}
			}else {
				test[i-1]=0;
			}
			
		}
		if(test[0]==n) {
			Arrays.fill(test, n);
		}else {
			if(test[0]!=0&&test[n-1]!=0) {
				test[n-1]=test[0]+1;
				for(int i=n-2;i>=0;i--) {
					if(test[i]==0)
						break;
					else {
						test[i]=test[i+1]+1;
					}
				}
			}
		}
		for(int i=0;i<n;i++) {
			if(test[i]%2==0&&test[i]!=n) {
				out.println("First");
			}else if(test[i]%2==0&&test[i]==n) {
				out.println("Second");
			}else if(test[i]%2!=0&&test[i]!=n) {
				out.println("Second");
			}else if(test[i]%2!=0&&test[i]==n) {
				out.println("First");
			}
		}
		out.flush();
		out.close();

	}


}

为了便于大家的理解,附上我的另一组代码,虽然没有ac,但思路是正确的就是有点超时:

package 登;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class D_2 {
	static int n;
	public static void main(String[] args) throws NumberFormatException, IOException {
		// TODO Auto-generated method stub
		
		BufferedReader sc=new BufferedReader(new InputStreamReader(System.in));
		PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
		n=Integer.parseInt(sc.readLine());
		String s=sc.readLine();
		String[] ss=s.split(" ");
		int[] ch=new int[n];
		for(int i=0;i<n;i++) {
			ch[i]=Integer.parseInt(ss[i]);
		}
		for(int i=0;i<n;i++) {
			int m=countOne(ch,i);
			if(m%2==0&&m!=n) {
				out.println("First");
			}else if(m%2==0&&m==n) {
				out.println("Second");
			}else if(m%2!=0&&m!=n) {
				out.println("Second");
			}else if(m%2!=0&&m==n) {
				out.println("First");
			}
		}
		out.flush();
		out.close();

	}

	private static int countOne(int[] ch, int i) {
		// TODO Auto-generated method stub
		int count=0;
		if(ch[i]!=1)return count;
		else {
			while(ch[i]==1) {
				if(count==n) {
					break;
				}
				count++;
				i++;
				if(i==n) {
					i=0;
				}
			}
			return count;
		}
		
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值