• 2022牛客多校六 M-Z-Game on grid(动态规划)


    题目:

    样例输入: 

    1. 2
    2. 3 3
    3. ..B
    4. ..B
    5. BB.
    6. 1 3
    7. ...

    样例输出:

    1. no no yes
    2. no yes no

    题意:两个人在 𝑁𝑀  N∗M 的网格上轮流移动一个棋子。棋子初始位为 (1,1)  (1,1) ,每次只能向某一维的正方向移动一格。网格上有一些特殊点,移到标 ’A’ 的点先手胜,移到标 ‘B’ 的点先手败,没有移到特殊点且不能再移动棋子则为平局。问先手是否有必胜、必平局、必败的策略。

    分析:这是一道动态规划的题目,设f[i][j][0/1/2]=true/false表示从(i,j)走到(n,m)Alice(有/无)(必胜/平局/必败)方案,由于三种方案转移方法是相同的,我接下来就拿必胜状态来进行动态方程的推导。我们从位置(i,j)只能走到(i+1,j)和(i,j+1)两个格子其中的一个。看到这个状态表示也能大概想到我们的动态转移方程是逆着进行的,也就是从后往前递推,所以当我们更新到位置(i,j)时,位置(i+1,j)和位置(i,j+1)的状态就已经被更新好了,那么假如走到位置(i,j)时轮到Alice操作了,也就是(i+j)是偶数的情况,由于Alice的操作是我们可控的,所以只要位置(i+1,j)和位置(i,j+1)有一个位置是必胜态,那么Alice就能获胜,所以也就是说f[i][j][0]=f[i+1][j][0]|f[i][j+1][0],当然要保证位置(i+1,j)和位置(i,j+1)是合法的,也就是说i+1<=n,j+1<=m,那么假如走到位置(i,j)时轮到Bob操作了,由于Bob的操作是不可控的,所以我们只有同时保证位置(i+1,j)和位置(i,j+1)都是必胜态我们才能保证我们想要的结果发生,也就是说f[i][j][0]=f[i+1][j][0]&f[i][j+1][0],同样的也需要保证位置是合法的。我们按照上面的分析思路同样可以分析平局和必败的情况,这里就不赘述了,细节见代码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. using namespace std;
    10. const int N=5e2+10;
    11. char s[N][N];
    12. bool f[N][N][3];//f[i][j][0/1/2]=true/false表示从(i,j)走到(n,m)Alice有/无必胜/平局/必败方案
    13. int main()
    14. {
    15. int T;
    16. cin>>T;
    17. while(T--)
    18. {
    19. int n,m;
    20. scanf("%d%d",&n,&m);
    21. for(int i=1;i<=n;i++)
    22. {
    23. scanf("%s",s[i]+1);
    24. for(int j=1;j<=m;j++)
    25. for(int k=0;k<3;k++)
    26. f[i][j][k]=false;
    27. }
    28. for(int i=n;i>=1;i--)
    29. for(int j=m;j>=1;j--)
    30. {
    31. if(s[i][j]=='A') f[i][j][0]=true;
    32. else if(s[i][j]=='B') f[i][j][2]=true;
    33. else//s[i][j]=='.'
    34. {
    35. if(i==n&&j==m)
    36. {
    37. f[i][j][1]=true;//特判不能走的情况
    38. continue;
    39. }
    40. if((i+j)&1)//轮到Bob走
    41. {
    42. for(int k=0;k<3;k++)
    43. f[i][j][k]=true;
    44. if(i+1<=n)
    45. for(int k=0;k<3;k++)
    46. f[i][j][k]&=f[i+1][j][k];
    47. if(j+1<=m)
    48. for(int k=0;k<3;k++)
    49. f[i][j][k]&=f[i][j+1][k];
    50. }
    51. else//轮到Alice走
    52. {
    53. if(i+1<=n)
    54. for(int k=0;k<3;k++)
    55. f[i][j][k]|=f[i+1][j][k];
    56. if(j+1<=m)
    57. for(int k=0;k<3;k++)
    58. f[i][j][k]|=f[i][j+1][k];
    59. }
    60. }
    61. }
    62. if(f[1][1][0]) printf("yes ");
    63. else printf("no ");
    64. if(f[1][1][1]) printf("yes ");
    65. else printf("no ");
    66. if(f[1][1][2]) puts("yes");
    67. else puts("no");
    68. }
    69. return 0;
    70. }

  • 相关阅读:
    LeetCode:字符串篇
    MyBatis获取参数值的两种方式
    MASM32v11编程调用Process32First失败: 程序发出命令,但命令长度不正确
    thinkphp漏洞总结
    macOS Tor 在启动期间退出
    mysql高阶语句(一)
    MySQL MHA高可用配置及故障切换
    [Jenkins] Docker 安装Jenkins及迁移流程
    Zigbee开发笔记- IAR的使用
    力扣(LeetCode)311. 稀疏矩阵的乘法(2022.11.08)
  • 原文地址:https://blog.csdn.net/AC__dream/article/details/126201777