騰訊模擬題之取球問題
阿新 • • 發佈:2019-02-15
問題描述:假設有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;
}
}