海贼007

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

【题意】:两个人玩游戏,给定一个数,减去他的因子(除了1和他本身外)得到一个新数,两个人轮流玩游戏.最后谁无数可减即为失败。  

【算法】根据N/P分析:

1.标记出1-1000所有的质数,这都是必败点P

2.从小到大,如果不是质数,则根据N/P关系判断他是N还是P

3.直到n为止。

一个P/N分析的例子http://blog.sina.com.cn/s/blog_87ad13a10100y3ay.html

【编码调试BUG

1.49行,生成prime数组的时候,循环结束条件应该是i<=n/2,少考虑了等号的情况;

2.23行,j<i-1写成了j<i,忽略掉了1。

 

Java代码】来自菜鸟 

 1 import java.util.*;
 2 import java.util.regex.*;
 3 import java.text.*;
 4 import java.math.*;
 5 
 6 
 7 public class TheNumberGameDivTwo
 8 {
 9     boolean[] prime;
10     public String find(int n)
11     {
12         int i,j,temp;
13         boolean[] p = new boolean[n+1];
14         
15         getPrimes(n);
16         //init all primes to P
17         for(i=1;i<=n;i++)
18             p[i]=prime[i];
19         
20         for(i=1;i<=n;i++){
21             if(p[i])
22                 continue;
23             for(j=2;j<i-1;j++){
24                 if(p[j]){
25                     temp=i-j;
26                     if(i%temp==0)
27                         break;//p[i] is N
28                 }
29             }
30             if(j==i+1)
31                 p[i]=true;//p[i] is P
32         }
33         if(p[n])
34             return "Brus";
35         else
36             return "John";
37     }
38     
39     public void getPrimes(int n){
40         prime = new boolean[n+1];
41         int i,j;
42         
43         for(i=1;i<=n;i++)
44             prime[i]=true;
45         
46         prime[0]=prime[1]=false;
47         
48         for(i=2;i<=n/2;i++){
49             if(!prime[i])
50                 continue;
51             for(j=i+i;j<=n;){
52                 prime[j]=false;
53                 j+=i;
54             }
55         }        
56     }
57 }
58 //Powered by KawigiEdit 2.1.4 (beta) modified by pivanof!
View Code

【改进版1】

【算法】

1.从小到大,则根据N/P关系判断他是N还是P(类似动态规划的填表)。

2.直到n为止。

【分析】

1.无需求出prime,因为算法可以保证所有的prime都为P。

 1 import java.util.*;
 2 import java.util.regex.*;
 3 import java.text.*;
 4 import java.math.*;
 5 
 6 
 7 public class TheNumberGameDivTwo
 8 {
 9     public String find(int n)
10     {
11         int i,j;
12         boolean[] p = new boolean[n+1];
13         
14         p[1]=true;
15         for(i=2;i<=n;i++){
16             for(j=2;j<i;j++){
17                 if(i%j==0){
18                     if(p[i-j]==true){
19                         p[i]=false;
20                         break;
21                     }
22                 }
23             }
24             if(j==i)
25                 p[i]=true;
26 
27         }
28         if(p[n])
29             return "Brus";
30         else
31             return "John";
32     }
33     
34 
35 }
36 //Powered by KawigiEdit 2.1.4 (beta) modified by pivanof!
View Code

【改进版2】实现时有点小区别,算法不变

 1 import java.util.*;
 2 import java.util.regex.*;
 3 import java.text.*;
 4 import java.math.*;
 5 
 6 
 7 public class TheNumberGameDivTwo
 8 {
 9     public String find(int n)
10     {
11         int i,j;
12         boolean[] p = new boolean[n+1];
13         
14         
15         for(i=1;i<=n;i++){
16             for(j=i/2;j<i-1;j++){
17                 if(p[j]){
18                     if(i%(i-j)==0)
19                         break;//p[i] is N
20                 }
21             }
22             if(j==i-1)
23                 p[i]=true;//p[i] is P
24         }
25         if(p[n])
26             return "Brus";
27         else
28             return "John";
29     }
30 }
31 //Powered by KawigiEdit 2.1.4 (beta) modified by pivanof!
View Code

【Java代码】来自大神

【分析】

1.大神采用的是动态规划的递归实现。

2.P问题对应memo[i]=0,N问题对应memo[i]=1。

3.divisors(n)方法用于获取n的所有除数。

【学习】

1.Arrays.fill()这个方法不错啊,有点像C里的memset。

import java.util.*; 

public class TheNumberGameDivTwo { 

  ArrayList<Integer> divisors(int n) { 
    ArrayList<Integer> res = new ArrayList<Integer>(); 
    for (int i = 2; i * i <= n; i++) { 
      if (n % i == 0) { 
        res.add(i); 
        if (!res.contains(n / i)) 
          res.add(n / i); 
      } 
    } 
    return res; 
  } 

  int[] memo; 

  public int can(int n) { 
    if (n == 1 || n == 2 || n == 3) 
      return 0; 
    if (memo[n] != -1) 
      return memo[n]; 
    int res = 0; 
    ArrayList<Integer> divs = divisors(n); 
    for (int i = 0; i < divs.size(); i++) { 
      res |= can(n - (int)(divs.get(i))) ^ 1; 
    } 
    return memo[n] = res; 
  } 

  public String find(int n) { 
    memo = new int[n + 2]; 
    Arrays.fill(memo, -1); 
    return can(n) > 0 ? "John" : "Brus"; 
  } 

} 



// Powered by FileEdit
// Powered by moj 4.17 [modified TZTester]
// Powered by CodeProcessor
View Code

C++代码】来自大神

【分析】

1.大神也是DP的递归实现。

2.代码好简洁,好帅气!

#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<algorithm>
#include<sstream>
#include<iomanip>
#include<cstring>
#include<bitset>
#include<fstream>
#include<cmath>
#include<cassert>
#include <stdio.h>
#include<ctype.h>
#include<ctime>
using namespace std ;
#define rep(i,n,m) for( int i = (int) n ; i < (int) m ; ++i )
 
#define mems(arr,v) memset(arr,v,sizeof arr)
 
class TheNumberGameDivTwo {
public:
  string find(int n);
};
int dp[10001];
int rec(int n) {
  if(n == 1)
    return false;
  if(dp[n] != -1)
    return dp[n];
  rep(i, 2, n)
    if(n % i == 0 && !rec(n - i))
      return dp[n] = true;
  return dp[n] = false;
}
string TheNumberGameDivTwo::find(int n) {
  mems(dp, -1);
  return rec(n) ? "John" : "Brus" ;
}
 
 
 
//Powered by KawigiEdit 2.1.8 (beta) modified by pivanof!
//With unused code cleaner (beta) by ahmed_aly
View Code

 

【总结】

1.N/P属于博弈论范畴,应该用DP实现。

 

    

posted on 2013-07-27 16:45  wzhscript  阅读(257)  评论(0编辑  收藏  举报