将棋的规则

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将棋的规则相关的知识,希望对你有一定的参考价值。

  历史
  将棋的始祖是印度的恰图兰卡,主流观点认为从东南亚传入,又受中国象棋的影响[1], 演变成与泰国象棋类同的平安将棋,之后分支成小将棋、中将棋、大将棋、大大将棋、天竺大将棋、摩诃大大将棋、泰将棋、大局将棋等诸多日本将棋变体,传说再由后奈良天皇改良小将棋,去除棋子醉象,成为现在流行的本将棋。

  [编辑] 规则

  [编辑] 棋盘
  将棋的棋盘是一个由10条横线及10条直线相交的方格阵,而棋子则置於方格之内,也就是9列9行的棋盘。 靠近自己的3列是本阵,远离自己而靠近对手的3列是敌阵。

  [编辑] 棋子
  将棋的棋子呈钟形,前端较尖。和中国象棋及国际象棋不同,将棋是以棋子前端的指的方向来区别所属。将棋共有八种棋子。每种棋子均有独特的简称及走法,分述如下:

  名称 简称 移动方法 备注
  王将或玉将 玉 ○ ○ ○
  ○ 玉 ○
  ○ ○ ○
  可以向任何方向行走,但只能走一格 如此棋被捉死则玩家输掉此局
  飞车 飞 ■ │ ■
  — 飞 —
  ■ │ ■
  可以横向或纵向行走任意距离,但不能斜走
  不能跨过别的棋子
  可以升级成龙王。参见升级一节
  角行 角 \ ■ /
  ■ 角 ■
  / ■ \
  可以沿对角线行走任意距离,但不能横向或纵向行走
  不能跨过别的棋子
  可以升级成龙马。参见升级一节
  金将 金 ○ ○ ○
  ○ 金 ○
  ■ ○ ■
  可以向前、左前、右前、左、右或后行走一格
  银将 银 ○ ○ ○
  ■ 银 ■
  ○ ■ ○
  可以沿对角线或正前方行走一格 可以升级成成银。参见升级一节
  桂马 桂 ☆ ■ ☆
  ■ ■ ■
  ■ 桂 ■
  只能走到前两格的左方或右方
  中间的棋子并不阻碍桂马前进
  可以升级成成桂。参见升级一节
  香车 香 ■ │ ■
  ■ 香 ■
  ■ ■ ■
  可向前走任意步数
  不能跨过别的棋子
  可以升级成成香。参见升级一节
  步兵 步 ■ ○ ■
  ■ 步 ■
  ■ ■ ■
  只能向前走一格 可以升级成と金。参见升级一节

  [编辑] 开局配置
  当一局将棋开始时,双方各有二十只棋子,分布如下:

  香 桂 银 金 玉 金 银 桂 香
  ■ 飞 ■ ■ ■ ■ ■ 角 ■
  步 步 步 步 步 步 步 步 步
  ■ ■ ■ ■ ■ ■ ■ ■ ■
  ■ ■ ■ ■ ■ ■ ■ ■ ■
  ■ ■ ■ ■ ■ ■ ■ ■ ■
  步 步 步 步 步 步 步 步 步
  ■ 角 ■ ■ ■ ■ ■ 飞 ■
  香 桂 银 金 王 金 银 桂 香

  以上的棋子配置可用以下文字表述:

  王将或玉将放置於棋盘中路最接近玩家的一行。
  两枚金将置於王将或玉将的旁边。
  两枚银将置於金将的旁边。
  两枚桂马置於银将的旁边。
  两枚香车置於桂马的旁边。
  在第二行,放置一枚角行於左及一枚飞车於右。两枚棋子的下方均为桂马。
  九枚步兵全部放置於第三行。
  需要留意的是,将棋有让子制度,以上布置只在没有让子的情况下适用。

  [编辑] 棋谱记法
  日式的记法通常只记录棋子移动后的座标,先写筋(横座标,相等於中国象棋的路)、再写段(直座标,相等於中国象棋的线),最后写棋子名称。

  座标以先手方看,横座标是从最右行到最左行,用阿拉伯数目字表示,为1到9;直座标是从最上列到最下列,用汉字表示,为一到九。第一至第三段属於后手方的自阵/先手方的敌阵,第七至第九段属於先手方的自阵/后手方的敌阵。

  有别於中国象棋,将棋一方走一著棋为之一「手」,双方各走一著共计两手,象棋五十回合即等於将棋一百手。若手数为单数时,即由先手走子,属先手番,手数为双数时,由后手走子,属后手番。

  棋谱记录先手著法以▲表示,后手著法以▽表示,举例如下:

  1 ▲2六步 2 ▽3四步 3 ▲7六步 4 ▽8八角成 5 ▲同 银 6 ▽2二银 7 ▲5八金右

  每一手棋先记录棋子移动后的位置,先写筋,后写段,再记录该棋子的名称。譬如先手第一手推进飞车前的步兵,著法为「▲2六步」,后手推进角筋(该方角行位在的直行)上的步兵,著法为「▽3四步」,如此类推。

  如其中一手棋走到的位置与对方上一手棋所到的位置一样并取去对方的棋子,则用「同」表示位置。

  如有一手棋走进敌阵并升变为另一棋种, 则在该棋子加上「成」字,如「▲2一飞成」;若选择不成,则加上「不成」二字,如「▽4七银不成」。升级的棋子则用其新的名字记录,如王、马、成银、成香等。

  若将棋子打入到棋盘时,并无其他一样的棋子可走到该格,则无需特别注释,否则要加上一个「打」字,如「▲4五桂打」。参见打入及吃子一节。

  另外,若遇到棋盘上多於一个相同兵种的棋子可走到同格,如先手分别位於4九及6九的金将均可则走到玉将前的5八位,则分别以各个棋子的位置、方向加以注释,方法如下:

  棋子从左边向右走,以「左」表示;
  棋子从右边向左走,以「右」表示;
  棋子从后面向前直进,以「直」表示;
  棋子从侧面向前走,不论左右,均以「上」表示;
  棋子向横移,以「寄」表示;
  棋子往后退,以「引」表示。

  [编辑] 其他规则

  [编辑] 升级
  将棋的棋子设有升级制度。除了王将 (玉将) 、金将及已经升级的棋子外,所有棋子都可以升级。

  当一枚可升级的棋子移进或移出敌阵(位於距离棋手最远的三行)时,除特殊情况外,棋手可以选择把棋子翻转升级(或保持原状)。若棋子刚打入敌阵,则要多走一步才可升级。

  升级的详情如下:

  飞车升级为龙王 (简称龙)。除可纵向或横向行走任意步数外,亦可兼容王将 (玉将)的步法。
  角行升级为龙马 (简称马)。除可沿对角线行走任意步数外,亦可兼容王将 (玉将)的步法。
  银将、桂马、香车及步兵在升级后均会改依金将的走法,并不会保留原有的活动能力。
  银将升级后称为成银,成银亦可记作「全」。
  桂马升级后称为成桂,成桂亦可记作「圭」或「今」。进入敌阵最底的二行时必须自动升级。
  香车升级后称为成香,成香亦可记作「杏」或「个」。进入敌阵最底行时必须自动升级。
  步兵升级后称为と金(三省堂大辞林第二版:と金或と为汉字「成金」之略称)。进入敌阵最底行时必须自动升级。

  [编辑] 吃子及打入
  本将棋最特别的是棋手可以花一手将己方吃掉的棋子放回棋盘成为己方棋子,这在日文称为打入,大幅提高了将棋的复杂度。当一枚已升级的棋子被吃时,它的升级会被取消,打入时用原先的棋种表示。

  打入有四项限制:

  刚打入的棋子即使落在敌阵亦不能马上升级,一定要以后多下一手才行。
  不能把被吃的棋子打入在一些不能再走的位置。例如步兵、香车等都不能落在敌阵的底线;桂马不能落在敌阵的底线及其对上一线。
  步兵不能打入於已有己方(未升级的) 步兵的一路,这一种犯规称为二步。
  步兵打入时不能立刻将死对方,这一种犯规称为打步诘;反之若不会立刻将死则不犯规,此称为打步将。

  [编辑] 犯规
  在将棋当中,在不能升级的情况下为棋子升级、重覆四次局面的连将、将两个未升级的己方步兵置於同一纵路(日本略称「二步」)、破坏打入的限制、连下多於一手、对方王手时没有「应将」、或移开自己的棋子令到自己的王将自动被王手、违反棋子的允许行法(如角行不依斜线走)、超时等皆属犯规,其中以「二步」在日本的将棋职业赛中最为常见,自一九七七年迄今,在日本的将棋职业赛中已有44次「二步」的记录。

  [编辑] 将、将死
  如能下了能擒拿对方王将的一手,亦即象棋中的将军,则称为王手。被反将则是称为逆王手。王将不能逃脱,则此手构成诘み,亦即象棋的将死。将死对方的玩家胜出此局。

  若下了一手没有王手,但对方无论如何防御都会在下一手被将死,则称为必至。

  将棋容许连将但是不能重复同样的手法长照(长将),若双方重复循环同样的方式照将、应照达四次时,则照将方违规,判负。 举例说明,若甲方以飞车照将,乙方把玉将往左移一格,甲方又将飞车右移一格照将,乙方又把玉将往右移一格,甲方又将飞车左移一格照将......如此重复循环到第四次时,则甲方违规,判负。此规则在日本称为「连続王手の千日手」。

  [编辑] 将棋对局的结束
  除了将死外,将棋尚可於以下情况结束:

  其中一方行违规步时,犯规的玩家在正式比赛中会被直接判为败北。
  双方重复循环同样的著法,使得局面没有进一步变化达四次时,则视为和局。此规则在日本称为「千日手」。
  如双方的王将均於升级区内,且无法将死对方时,对局结束。双方需为自己拥有的棋子计分,计分方法为:王将不计分、角行及飞车各计五分,其他棋子各计一分。升级的棋子不会额外加分。如只有一方得分少於 24 则少分的一方判为负,否则不分胜负。
  在正式比赛中如有不分胜负的情况,双方需重赛并对调行子先后次序 (以至减少时限)。业余比赛则一般判和了事。

  [编辑] 让子
  为了让相对较弱的棋手也有获胜的机会,较强的棋手有时会让子(日文称为驹落)。在让子的情况下,让子方(即上手)必须在开局时永久除去自己一部分的棋子(即不能以任何方式将之放上棋盘)。不过,在国际赛上,让子并不会因为兵力上的差异而为相对较弱的棋手造成明显的优势。较常见的让子局会按照严重程度递增,现胪列如下:

  让香局与平局(日文称为平手)交替连下(日文称为半香)
  除去左旁香车(日文称为香落或左香落)
  除去角行(日文称为角落或角行落)
  除去飞车(日文称为飞落或飞车落)
  除去飞车与左旁香车(日文称为飞香落)
  除去飞车与角行(日文称为二枚落)
  除去飞车、角行与左旁香车(日文称为三枚落)
  除去飞车、角行与香车两乘(日文称为四枚落)
  除去飞车、角行、香车两乘与桂马两匹(日文称为六枚落)

  其他的让子局偶然会出现。最严重的情况,是让子方在盘面只有一枚王将在正常位置,而驹台则有三枚步兵(日文称为步三兵)。

  在将棋不同的机制之下,让子严重程度与棋手等级差异之间的关系,并无公认的标准。但一般来说(尤其是对业余者而言),让子的严重程度应该约相等於双方等级之间的差距。例如差一个等级则让香,差两个则让角,如此类推。

  [编辑] 诘将棋
  将棋的排局在日文称为诘め将棋,过程中必须不断王手,不可千日手(相当於中国象棋的长将、长捉、长拦等不断重复局面的僵持状态),最末将死对方(若有特别声明可包括必至),相当於中国象棋的连将杀局。诘将棋不一定要将双方的王将都摆上,通常只摆防守的那一方的。因为「王」字有时难以分辨上下,故在只有一个王将的排局中,例必把玉将摆上。有玉将的一方叫做玉方(或受方),无玉将的一方叫做攻方(或诘方)。一定是攻方先行。排局一般只会标明攻方的持子,除非有特别声明,否则假设玉方持有余下没标明的棋子(当然王将除外)。双方都有王将的排局则叫做双玉。诘将棋一般只显示棋盘右上角(即1一位附近)有关的部份。

  诘将棋的取胜手数,是以攻守双方的最佳著法计算。攻方的最佳著法,是指攻方能保证在若干最短的手数内将死玉方的一系列对策;而玉方的最佳著法,是指玉方能保证在若干最长的手数内保持不败的一系列对策。由攻守双方的最佳著手所构成的进程,就是棋局的正解。譬如说,「五手诘」的意思是指,当攻方在第一手下出最佳著法之后,无论以后玉方如何应,都必会在第三或第五手落败;同理,当玉方在第二手下出最佳著法之后,玉方都有办法在第四手保持不败。攻方的最佳著法不包括重复局面的废著;玉方的最佳著法不包括不能改变结局的打入。若攻方没有下出最佳著法,但因玉方同样没有下出最佳应手而让攻方其后获胜,则称为纷れ,意为侥幸。当攻方一直下出最佳著法,但玉方没有下出最佳应手、或下出正解以外的最佳应手,则称为变化。变化的手数一定不会长过正解。当玉方一直下出最佳应手,但攻方在某一手可以有正解以外的著法保证获胜,则称为余诘。若无论攻方如何出手,玉方都有办法逃避败局,则称为不诘。攻方的持驹(不论是一开始标明抑或中途吃进)在正解的最后一手尚未用完,或正解以外有余诘或不诘,则称为不完全作。

  诘将棋具增进将棋功力的实用价值,亦具艺术价值。比起中国象棋排局崇尚和局的刚柔并济之美,诘将棋纯粹刚猛、紧凑。除了教学用的实用残局之外,中国象棋的排局例必摆上双方的将帅,故此解杀还杀是象棋排局的精粹。但日本的诘将棋只摆上一方的王将,故此玉方只能守或逃、不能反攻。另一方面,诘将棋即使是三手诘也可以很有趣味,但三步成杀的象棋排局却绝无仅有。象棋和将棋的妙趣,实乃各有千秋。诘将棋在江户时代就大量出现了相关书籍,其中的代表作包括将棋无双及将棋图巧。

  日本民间亦有像中国民间艺人依摆棋摊为生的江湖排局,称作大道诘将棋,其中尤以香步问题最为广泛研究。

  [编辑] 复杂度
  对日本将棋而言,9*9的棋盘的状态空间(State space)复杂度可达1071;而赛局树(Game tree)复杂度,亦可达10226 。整体的复杂度低於围棋但高於中国象棋与国际象棋。[2]

  [编辑] 发展

  本将棋当中可能出现的棋子表列。上行由左至右分别为龙王、飞车、王将、玉将、角行与龙马,而下行由左至右则分别为成香、香车、成银、银将、金将、桂马、成桂、步兵与成金。在中国大陆,青少年主要从接触到的日本漫画对日本将棋有些许了解。 1994年,中国北京开始有青少年活动中心教授日本将棋。次年,在北京京日饭店举行了第六届「龙王杯」日本将棋决赛的第三轮比赛(决赛为七局四胜制),由当时的六冠王羽生善治对战挑战者,在比赛的同时还举行了多场中日青少年间的将棋比赛。
  1. 棋的种类与排法

  棋的种类 王将
  x1 玉将
  x1 飞车
  x2 角行
  x2 金将
  x4
  银将
  x4 桂马
  x4 香车
  x4 步兵
  x18

  棋的排法
  将棋(2人play)玩法为自己与对手各自拥有20个棋子,在9×9=81个格子构成的将棋盘上对决。一人轮流移动自己的棋,先取了对手的玉(王)为胜方。

  还有,日本的象棋可以将对手的棋吃了之后再当成自己的棋使用的玩法。

  棋的排法
参考技术A http://baike.baidu.com/view/25991.htm

LeetCode 第 165 场周赛

LeetCode 第 165 场周赛

5275. 找出井字棋的获胜者

5276. 不浪费原料的汉堡制作方案

5277. 统计全为 1 的正方形子矩阵

5278. 分割回文串 III

C 暴力做的,只能说数据不充分

找出井字棋的获胜者4

题目描述 Description

A 和 B 在一个 3 x 3 的网格上玩井字棋。

井字棋游戏的规则如下:

玩家轮流将棋子放在空方格 (" ") 上。
第一个玩家 A 总是用 "X" 作为棋子,而第二个玩家 B 总是用 "O" 作为棋子。
"X" 和 "O" 只能放在空方格中,而不能放在已经被占用的方格上。
只要有 3 个相同的(非空)棋子排成一条直线(行、列、对角线)时,游戏结束。
如果所有方块都放满棋子(不为空),游戏也会结束。
游戏结束后,棋子无法再进行任何移动。

给你一个数组 moves,其中每个元素是大小为 2 的另一个数组(元素分别对应网格的行和列),它按照 A 和 B 的行动顺序(先 A 后 B)记录了两人各自的棋子位置。

如果游戏存在获胜者(A 或 B),就返回该游戏的获胜者;如果游戏以平局结束,则返回 "Draw";如果仍会有行动(游戏未结束),则返回 "Pending"。

你可以假设 moves 都 有效(遵循井字棋规则),网格最初是空的,A 将先行动。

样例输入与样例输出 Sample Input and Sample Output

示例 1:

  输入:moves = [[0,0],[2,0],[1,1],[2,1],[2,2]]
  输出:"A"
  解释:"A" 获胜,他总是先走。
  "X  "    "X  "    "X  "    "X  "    "X  "
  "   " -> "   " -> " X " -> " X " -> " X "
  "   "    "O  "    "O  "    "OO "    "OOX"

示例 2:

  输入:moves = [[0,0],[1,1],[0,1],[0,2],[1,0],[2,0]]
  输出:"B"
  解释:"B" 获胜。
  "X  "    "X  "    "XX "    "XXO"    "XXO"    "XXO"
  "   " -> " O " -> " O " -> " O " -> "XO " -> "XO "
  "   "    "   "    "   "    "   "    "   "    "O  "

示例 3:

输入:moves = [[0,0],[1,1],[2,0],[1,0],[1,2],[2,1],[0,1],[0,2],[2,2]]
输出:"Draw"
输出:由于没有办法再行动,游戏以平局结束。
"XXO"
"OOX"
"XOX"

示例 4:

输入:moves = [[0,0],[1,1]]
输出:"Pending"
解释:游戏还没有结束。
"X "
" O "
" "

提示 Hint

提示:

1 <= moves.length <= 9
moves[i].length == 2
0 <= moves[i][j] <= 2
moves 里没有重复的元素。
moves 遵循井字棋的规则。

题解

模拟即可,考虑到 3x3 有看到位运算的做法

代码

class Solution {
 public:

  int run(int g[3][3], vector<int>&move, int val) {
    g[move[0]][move[1]] = val;
    int t = 0, ans = 0;
    for(int i = move[0]; i < 3; ++i) {
      if(g[i][move[1]] == val)
        t++;
      else
        break;
    }
    for(int i = move[0] - 1; i >= 0; --i) {
      if(g[i][move[1]] == val)
        t++;
      else
        break;
    }
    ans = max(ans, t);
    t = 0;

    for(int i = move[1]; i < 3; ++i) {
      if(g[move[0]][i] == val)
        t++;
      else
        break;
    }
    for(int i = move[1] - 1; i >= 0; --i) {
      if(g[move[0]][i] == val)
        t++;
      else
        break;
    }
    ans = max(ans, t);
    t = 0;

    for(int i = 0; i + move[0] < 3 && i + move[1] < 3; ++i) {
      if(g[i + move[0]][i + move[1]] == val)
        t++;
      else
        break;
    }
    for(int i = -1; i + move[0] >= 0 && i + move[1] >= 0; --i) {
      if(g[i + move[0]][i + move[1]] == val)
        t++;
      else
        break;
    }
    ans = max(ans, t);
    t = 0;

    for(int i = 0; i + move[0] < 3 && move[1] - i >= 0; ++i) {
      if(g[i + move[0]][-i + move[1]] == val)
        t++;
      else
        break;
    }
    for(int i = -1; i + move[0] >= 0 && move[1] - i < 3 ; --i) {
      if(g[i + move[0]][-i + move[1]] == val)
        t++;
      else
        break;
    }
    ans = max(ans, t);
    t = 0;

    return ans;
  }
  bool finished(int g[3][3]) {
    for(int i = 0; i < 3; ++i)
      for(int j = 0; j < 3; ++j)
        if(g[i][j] == 0)
          return false;
    return true;
  }
  string tictactoe(vector<vector<int>>& moves) {
    int g[3][3];
    memset(g, 0, sizeof(g));
    for(int i = 0, n = moves.size(); i < n; ++i) {
      if(run(g, moves[i], i % 2 + 1) > 2)
        return (i & 1) ?  string("B") : string("A");
    }
    return finished(g) ? string("Draw") : string("Pending");
  }
};

不浪费原料的汉堡制作方案4

5276. 不浪费原料的汉堡制作方案

题目描述 Description

圣诞活动预热开始啦,汉堡店推出了全新的汉堡套餐。为了避免浪费原料,请你帮他们制定合适的制作计划。

给你两个整数 tomatoSlices 和 cheeseSlices,分别表示番茄片和奶酪片的数目。不同汉堡的原料搭配如下:

巨无霸汉堡:4 片番茄和 1 片奶酪
小皇堡:2 片番茄和 1 片奶酪

请你以 [total_jumbo, total_small]([巨无霸汉堡总数,小皇堡总数])的格式返回恰当的制作方案,使得剩下的番茄片 tomatoSlices 和奶酪片 cheeseSlices 的数量都是 0。

如果无法使剩下的番茄片 tomatoSlices 和奶酪片 cheeseSlices 的数量为 0,就请返回 []。

样例输入与样例输出 Sample Input and Sample Output

示例 1:

输入:tomatoSlices = 16, cheeseSlices = 7
输出:[1,6]
解释:制作 1 个巨无霸汉堡和 6 个小皇堡需要 41 + 26 = 16 片番茄和 1 + 6 = 7 片奶酪。不会剩下原料。

示例 2:

输入:tomatoSlices = 17, cheeseSlices = 4
输出:[]
解释:只制作小皇堡和巨无霸汉堡无法用光全部原料。

示例 3:

输入:tomatoSlices = 4, cheeseSlices = 17
输出:[]
解释:制作 1 个巨无霸汉堡会剩下 16 片奶酪,制作 2 个小皇堡会剩下 15 片奶酪。

示例 4:

输入:tomatoSlices = 0, cheeseSlices = 0
输出:[0,0]

示例 5:

输入:tomatoSlices = 2, cheeseSlices = 1
输出:[0,1]

提示 Hint

提示:

0 <= tomatoSlices <= 10^7
0 <= cheeseSlices <= 10^7

题解

先考虑全部用作小皇堡,剩下的每 2 片番茄将一个小皇堡换成巨无霸汉堡。注意边界和特判。

代码

class Solution {
 public:
  vector<int> numOfBurgers(int tomatoSlices, int cheeseSlices) {
    if(tomatoSlices > cheeseSlices * 4)
      return vector<int> {};
    vector<int> ans(2);
    ans[1] = cheeseSlices;
    tomatoSlices -= 2 * cheeseSlices;
    if(tomatoSlices < 0 || (tomatoSlices & 1))
      return vector<int> {};
    ans[1] -= tomatoSlices / 2;
    ans[0] += tomatoSlices / 2;
    tomatoSlices -= tomatoSlices - (tomatoSlices & 1);
    if(tomatoSlices != 0)
      return vector<int> {};
    return ans;
  }
};

统计全为 1 的正方形子矩阵5

5277. 统计全为 1 的正方形子矩阵

题目描述 Description

给你一个 m * n 的矩阵,矩阵中的元素不是 0 就是 1,请你统计并返回其中完全由 1 组成的 正方形 子矩阵的个数。

样例输入与样例输出 Sample Input and Sample Output

示例 1:

输入:matrix =
[
[0,1,1,1],
[1,1,1,1],
[0,1,1,1]
]
输出:15
解释:
边长为 1 的正方形有 10 个。
边长为 2 的正方形有 4 个。
边长为 3 的正方形有 1 个。
正方形的总数 = 10 + 4 + 1 = 15.

示例 2:

输入:matrix =
[
[1,0,1],
[1,1,0],
[1,1,0]
]
输出:7
解释:
边长为 1 的正方形有 6 个。
边长为 2 的正方形有 1 个。
正方形的总数 = 6 + 1 = 7.

提示 Hint

1 <= arr.length <= 300
1 <= arr[0].length <= 300
0 <= arr[i][j] <= 1

题解

暴力可过,显然数据强度不够。

代码

class Solution {
 public:
  int n, m;
  int countSquares(vector<vector<int>>& matrix) {
    n = matrix.size(), m = matrix[0].size();
    int ans(0);
    for(int i = 1, c; i <= min(n, m); ++i) {
      c = count(matrix, i);
      ans += c;
      if(!c)
        break;
    }
    return ans;
  }
  int count(vector<vector<int> >&matrix, int edgeLen) {
    int ans(0);
    for(int i = 0; i < n - edgeLen + 1; ++i) {
      for(int j = 0; j < m - edgeLen + 1; ++j)
        if(isSquareAllOne(matrix, i, j, edgeLen))
          ans++;
    }
    return ans;
  }

  bool isSquareAllOne(vector<vector<int>>&matrix, int x, int y, int edgeLen) {
    for(int i = 0; i < edgeLen; ++i) {
      for(int j = 0; j < edgeLen; ++j)
        if(!matrix[x + i][y + j])
          return false;
    }
    return true;
  }
};

分割回文串 III

5278. 分割回文串 III

题目描述 Description

给你一个由小写字母组成的字符串 s,和一个整数 k。

请你按下面的要求分割字符串:

首先,你可以将 s 中的部分字符修改为其他的小写英文字母。
接着,你需要把 s 分割成 k 个非空且不相交的子串,并且每个子串都是回文串。

请返回以这种方式分割字符串所需修改的最少字符数。

样例输入与样例输出 Sample Input and Sample Output

示例 1:

输入:s = "abc", k = 2
输出:1
解释:你可以把字符串分割成 "ab" 和 "c",并修改 "ab" 中的 1 个字符,将它变成回文串。

示例 2:

输入:s = "aabbc", k = 3
输出:0
解释:你可以把字符串分割成 "aa"、"bb" 和 "c",它们都是回文串。

示例 3:

输入:s = "leetcode", k = 8
输出:0

提示 Hint

1 <= k <= s.length <= 100
s 中只含有小写英文字母。

题解

dp[i][j] 表示以 i 结尾,分成 j 段的最少修改次数。枚举上一段结尾的位置 pre,dp[i][j] = min(dp[i][j],dp[pre][j-1])

代码

class Solution {
 public:
  int palindromePartition(string s, int k) {
    int dp[s.length()][k + 1];
    memset(dp, 0x3f, sizeof(dp));
    for(int i = 0; i < s.length(); ++i) { // end with s[i]
      for(int j = 1; j <= k && j <= i + 1; ++j) { // has j segments
        if(j == 1)
          dp[i][j] = transferCost(s, 0, i);
        else
          for(int pre = max(j - 2, 0); pre < i; ++pre) {
            dp[i][j] = min(dp[i][j], dp[pre][j - 1] + transferCost(s, pre + 1, i));
          }
      }
    }
    return dp[s.length() - 1][k];
  }
  int transferCost(string s, int l, int r) {
    int ans(0);
    for(int i = 0; i < (r - l + 1) / 2; ++i)
      if(s[i + l] != s[r - i])
        ans++;
    return ans;
  }
};

以上是关于将棋的规则的主要内容,如果未能解决你的问题,请参考以下文章

leetcode.1275找出井字棋的获胜者

悬线法——有套路的DP

三子棋

[ZJOI2007]棋盘制作

[ZJOI2007]棋盘制作

ZJOI2007棋盘制作 - 悬线法