亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 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;
}
}
};