1. 程式人生 > >騰訊模擬題之取球問題

騰訊模擬題之取球問題

問題描述:假設有16個球,有david和cavin兩個人輪流來取,每個人只能去1,3,6.先取完的為勝。由David先取,問David第一次去多少才能保證勝利。

首先要感謝湛總,這個思路是它提供的。
首先建立兩個建立,一個是必勝集,一個是必輸集。而且只考慮一個人,比如David,如果當前球的數量正好在必勝集中,那麼他一定可以取勝,假如自己在必輸集裡,假設Calvin智力正常,那David一定輸了。
首先他們之間的轉換關係如下:如果一個數,該數-1,-3,-6只要有一個在必輸集裡面,那麼這個點就加入必勝集中。原因很簡單,David取了一個數之後,將某個必輸的結果留給了Calvin,那這個數對David而言自然就穩贏了,因為David不是傻子,他取的數一定對它是最有利的。同理,如果一個數,該數-1,-3,-6之後這些數全在必勝集裡面,那他必輸。

所以經過一個迴圈之和,這兩個集合也就建立起來了,既然David先取,它只要選擇一個數,使餘下的數在必輸集裡面就OK了,因為這個必輸集是Calvin需要面對的。

程式碼如下:

package 騰訊模擬考.problem1;

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

/**
 * Created by dave on 2016/9/1.
 * 假設有16個球,有david和cavin兩個人輪流來取,每個人只能去1,3,6.先取完的為勝。由David先取,問David第一次去多少才能保證勝利
 */
public class Main { static int[] steps = new int[]{1,3,6}; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int count = scanner.nextInt(); int choose = doWork(count); System.out.println(choose); } private static int doWork
(int count){ Set<Integer> allowSet = new HashSet<>(); Set<Integer> failSet = new HashSet<>(); for(int tmp:steps) allowSet.add(tmp); for(int i = 1;i<count;i++){ if(allowSet.contains(i)) continue; if(checkIsAllowed(failSet,i)) allowSet.add(i); else if(checkIsFailed(allowSet,i)) failSet.add(i); } for(int tmp:steps){ if(failSet.contains(count-tmp)) return tmp; } return -1; } private static boolean checkIsAllowed(Set<Integer> set,int val){ for(int tmp:steps){ tmp = val-tmp; if(tmp > 0 && set.contains(tmp)) return true; } return false; } private static boolean checkIsFailed(Set<Integer> set,int val){ for(int tmp:steps){ tmp = val-tmp; if(tmp > 0 && !set.contains(tmp)) return false; } return true; } }