亞歷克斯和李用幾堆石子在做遊戲。偶數堆石子排成一行,每堆都有正整數顆石子 piles[i] 。
遊戲以誰手中的石子最多來決出勝負。石子的總數是奇數,所以沒有平局。
亞歷克斯和李輪流進行,亞歷克斯先開始。 每回合,玩家從行的開始或結束處取走整堆石頭。 這種情況一直持續到沒有更多的石子堆爲止,此時手中石子最多的玩家獲勝。
假設亞歷克斯和李都發揮出最佳水平,當亞歷克斯贏得比賽時返回 true ,當李贏得比賽時返回 false 。
示例:
輸入:[5,3,4,5]
輸出:true
解釋:
亞歷克斯先開始,只能拿前 5 顆或後 5 顆石子 。
假設他取了前 5 顆,這一行就變成了 [3,4,5] 。
如果李拿走前 3 顆,那麼剩下的是 [4,5],亞歷克斯拿走後 5 顆贏得 10 分。
如果李拿走後 5 顆,那麼剩下的是 [3,4],亞歷克斯拿走後 4 顆贏得 9 分。
這表明,取前 5 顆石子對亞歷克斯來說是一個勝利的舉動,所以我們返回 true 。
提示:
2 <= piles.length <= 500
piles.length 是偶數。
1 <= piles[i] <= 500
sum(piles) 是奇數。
class Solution {//dp[i][j]表示i~j先手能獲得最大值 sum[j+1]-sum[i]表示i~j的求和
public:
bool stoneGame(vector<int>& piles) {
int pSize=piles.size();
vector<vector<int>>dp(pSize,vector<int>(pSize,0));
vector<int>sum(pSize+1,0);
for(int i=1;i<=pSize;++i)
sum[i]=sum[i-1]+piles[i-1];
for(int i=0;i<pSize;++i)
dp[i][i]=piles[i];
for(int j=1,sumij;j<pSize;++j)//內外層循環遍歷初始值和結束值不會寫
for(int i=j-1;i>=0;--i){//草稿圖畫出二維矩陣,找到初始已知數據(對角線)和轉移推導順序(先那一行/列,再哪一列/行),最後確定最終結果是矩陣的哪個數據(一般四個角)或那一行/列數據的最值
sumij=sum[j+1]-sum[i];
dp[i][j]=max(sumij-dp[i+1][j],sumij-dp[i][j-1]);//轉移方程
}
return dp[0][pSize-1]>sum[pSize]-dp[0][pSize-1];
}
};
//內外層循環遍歷初始值和結束值
/*確定最終答案是dp[0][size-1]還是dp[size-1][0]還是dp[size-1][size-1]還是全部dp[i][j]中的某個最值。
確定每個數組元素是根據那些數組元素計算得到。從而確定先行還是先列,
確定行從上到下還是從下到上,
確定列從左到右還是從右到左,
只要涉及對對角線臨界值則引用上個循環的循環變量*/
//方法一<==>方法三
for(int j=1;j<size;++j){
for(int i=j-1;i>=0;--i){
dp[i][j]:第一列到隊後一列 依次 從對角線上一行到第一行
//方法二<==>方法四
for(int j=1;j<size;++j){//列
for(int i=0;i<j;++i){
dp[i][j]:第一列到隊後一列 依次 從第一行到對角線上一行
//方法三
for(int i=size-2;i>=0;--i)
for(int j=i+1;j<size;++j)
dp[i][j]:對角線最後上一行到第一行 依次 從對角線右一列到最後一列
//方法四
for(int i=size-2;i>=0;--i)
for(int j=size-1;j>=i+1;--j)
dp[i][j]:對角線最後上一行到第一行 依次 從最後一列到對角線右一列
class Solution {//根據畫出的二維草稿圖可以知道,二維dp可以優化成一維dp
public:
bool stoneGame(vector<int>& piles) {
int pSize=piles.size();
vector<int>dp(pSize,0);
vector<int>sum(pSize+1,0);
for(int i=1;i<=pSize;++i)
sum[i]=sum[i-1]+piles[i-1];
for(int i=0;i<pSize;++i)
dp[i]=piles[i];
for(int j=1,sumij;j<pSize;++j){
for(int i=j-1;i>=0;--i){
sumij=sum[j+1]-sum[i];
dp[j]=max(sumij-dp[j],sumij-dp[j-1]);
}
}
return dp[pSize-1]>sum[pSize]-dp[pSize-1];
}
};
兩個玩家分別扮演貓(Cat)和老鼠(Mouse)在無向圖上進行遊戲,他們輪流行動。
該圖按下述規則給出:graph[a] 是所有結點 b 的列表,使得 ab 是圖的一條邊。
老鼠從結點 1 開始並率先出發,貓從結點 2 開始且隨後出發,在結點 0 處有一個洞。
在每個玩家的回合中,他們必須沿着與他們所在位置相吻合的圖的一條邊移動。例如,如果老鼠位於結點 1,那麼它只能移動到 graph[1] 中的(任何)結點去。
此外,貓無法移動到洞(結點 0)裏。
然後,遊戲在出現以下三種情形之一時結束:
如果貓和老鼠佔據相同的結點,貓獲勝。
如果老鼠躲入洞裏,老鼠獲勝。
如果某一位置重複出現(即,玩家們的位置和移動順序都與上一個回合相同),遊戲平局。
給定 graph,並假設兩個玩家都以最佳狀態參與遊戲,如果老鼠獲勝,則返回 1;如果貓獲勝,則返回 2;如果平局,則返回 0。
示例:
輸入:[[2,5],[3],[0,4,5],[1,4,5],[2,3],[0,2,3]]
輸出:0
解釋:
4---3---1
| |
2---5
\ /
0
提示:
3 <= graph.length <= 200
保證 graph[1] 非空。
保證 graph[2] 包含非零元素。
class Solution {//平局的判定有誤,錯誤答案
vector<vector<int>> graph;
vector<vector<vector<int>>> visited,state;
enum result{
Draw,Mousewin,Catwin
};
enum turn{
Cat,Mouse
};
public:
int catMouseGame(vector<vector<int>>& graph) {
this->graph=graph;
visited.resize(200,vector<vector<int>>(200,vector<int>(2,0)));
state.resize(200,vector<vector<int>>(200,vector<int>(2,-1)));
return helper(1,2,1);
}
int helper(int m,int c,int player){//plyaer:1表示老鼠m,0表示貓c;
if(m==c)return Catwin;
else if(m==0)return Mousewin;
else if(visited[m][c][player])return Draw;
else if(state[m][c][player]!=-1)return state[m][c][player];
if(player==Mouse){
visited[m][c][player]=1;
int len=graph[m].size();
bool draw=false;
for(int i=0;i<len;++i){
//if(visited[graph[m][i]][c][Cat])continue;
int res=helper(graph[m][i],c,Cat);
if(res==Mousewin){
visited[m][c][player]=0;
return state[m][c][player]=Mousewin;
}
else if(res==Draw)
draw=true;
}
visited[m][c][player]=0;
return state[m][c][player]=draw?Draw:Catwin;
}
else{
visited[m][c][player]=1;
int len=graph[c].size();
bool draw=false;
for(int i=0;i<len;++i){
if(graph[c][i]==0)continue;//
int res=helper(m,graph[c][i],Mouse);
if(res==Catwin){
visited[m][c][player]=0;
return state[m][c][player]=Catwin;
}
else if(res==Draw)
draw=true;
}
visited[m][c][player]=0;
return state[m][c][player]=draw?Draw:Mousewin;
}
}
};
//狀態改爲(m,c,step),step表示走了多少步數
//步數大於2*graph.size()則判斷平局,原理未知
class Solution {
vector<vector<int>> graph;
vector<vector<vector<int>>>state;
enum result{
Draw,Mousewin,Catwin
};
enum turn{
Cat,Mouse
};
public:
int catMouseGame(vector<vector<int>>& graph) {
this->graph=graph;
state.resize(200,vector<vector<int>>(200,vector<int>(400,-1)));
return helper(1,2,1);
}
int helper(int m,int c,int step){//plyaer:1表示老鼠m,0表示貓c;
if(m==c)return Catwin;
if(m==0)return Mousewin;
if(step>graph.size())return Draw;
if(state[m][c][step]!=-1)return state[m][c][step];
if((step&1)==Mouse){
int len=graph[m].size();
bool draw=false;
for(int i=0;i<len;++i){
int res=helper(graph[m][i],c,step+1);
if(res==Mousewin){
return state[m][c][step]=Mousewin;
}
else if(res==Draw)
draw=true;
}
return state[m][c][step]=draw?Draw:Catwin;
}
else{
int len=graph[c].size();
bool draw=false;
for(int i=0;i<len;++i){
if(graph[c][i]==0)continue;//
int res=helper(m,graph[c][i],step+1);
if(res==Catwin){
return state[m][c][step]=Catwin;
}
else if(res==Draw)
draw=true;
}
return state[m][c][step]=draw?Draw:Mousewin;
}
}
};