题目链接

前置知识

P2825 [HEOI2016/TJOI2016]游戏
注:本题做法与上题做法类似
用到的算法:

  • 图论——二分图——匈牙利算法(最大匹配)
  • 建边——链式前向星。

解题思路

题目要求输出在题目给定的棋盘上能放最多的bishop(象)。
因为象的行走路线为对角线(斜线),不好写,所以我们将整个棋盘顺时针旋转45°(如图)。

由图可以看出,原先棋盘的对角线在顺时针旋转45°后变成了行和列。
由此,我们考虑行列匹配

一、输入

这里有一个巨坑点(作者这个蒟蒻被这个东西坑了一周)。
输入原棋盘时,建议一行一行的输入并且输入整个棋盘后再进行操作,否则有可能“听取WA声一片”。

二、存储旋转后的棋盘

我们建立一个结构体 n o d e node node 。

struct node{int xx,yy;int can;
}a[2200][2200];

a [ i ] [ j ] . x x a[i][j].xx a[i][j].xx 表示在原棋盘中 i i i 行 j j j 列的格子在旋转后位于 x x xx xx 行。
a [ i ] [ j ] . y y a[i][j].yy a[i][j].yy 表示旋转后位于 y y yy yy 列。

c a n can can 的值分三种:

  • c a n can can = 0
    该点可以放置象,且不会攻击到棋盘上原有棋子。
  • c a n can can = 1
    该点已有棋子,不可放置象,会阻挡除马以外的攻击范围。
  • c a n can can = 2
    该点未有棋子,但不可放置象,否则会攻击原有棋子或被原有棋子攻击,但不阻挡任何棋子的攻击范围

接下来,我们看具体如何操作。

1. 旋转后的格子位置

我们假设 n n n = 4 , m m m = 5。
先观察原棋盘格子的位置。

再看旋转后格子的位置。

不难发现,棋盘旋转45°后,原位置为 ( i , j ) (i,j) (i,j) 的格旋转到了 ( i + j − 1 , j + n − i ) (i+j-1,j+n-i) (i+j−1,j+n−i) 的位置。


2.标记攻击范围

国际象棋中一共有 6 种棋子:
K – king(国王),Q – queen(皇后),B – bishop(象,教主),N – knight(马、骑士),R – rook(车),P – pawn(兵)。

在原棋盘上,棋子的攻击范围分别如下:

我们将棋子所在格子的 c a n can can 标记为 1 1 1 , 将攻击范围标记为 2 2 2 。
注意:除马(knight)以外,其他棋子的攻击范围均会被棋子阻挡

如上图,车(R)的攻击范围被 兵(P) 阻挡,无法攻击到绿色格子。

你以为这道题的思路到此就结束了?不,还没有。
再细读题目,发现题目有这样一句话:

你需要避免的有 2 种情况: 你摆放的 bishop 之间的互相攻击以及你摆放的 bishop 与预先摆放好的棋子之间的互相攻击

所以我们不仅要标记棋子原有的攻击范围,还要再加上一个象的攻击范围。

三、二分图最大匹配

在【一】里讲过,旋转45°后,象的攻击范围由对角线变为行和列。由此,我们可以行列匹配。
我们开两个数组 r r r 和 c c c 。
r r r 数组存储象在新棋盘的水平方向上的每一个不同的攻击范围
c c c 数组存储象在新棋盘的竖直方向上的每一个不同的攻击范围
下面举个简单的例子来进一步理解。
红色点为 N N N 的攻击范围
我们设新棋盘的水平方向上不同的攻击范围的标记为 l e n r lenr lenr 。

  1. l e n r lenr lenr 每过一行需要加1,因为象在新棋盘上水平方向只能攻击到一行
  2. 如果遇到棋子, l e n r lenr lenr 也需要加1,因为棋子能阻挡象的攻击范围

则完成标记后的 r r r 数组如下:

标记 c c c 数组时同理,不作赘述。
下图为标记完成的 c c c 数组。

标记完成后,遍历新棋盘上的每一个点,若该点 ( i , j ) (i,j) (i,j) 可以放置象,则建立边连接 r i , j r_{i,j} ri,j​ 与 c i , j c_{i,j} ci,j​ (连接在该位置的象所能攻击到的两个方向的攻击范围编号)。

最后用匈牙利算法求最大匹配,就顺利切下这道题啦 !


下面结合代码来理解吧!

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
int head[1050000],to[1050000],ne[1050000],id;
int vis[20200],d[20200],n,m,maxx,ans;
int mp[2200][2200],r[2200][2200],c[2200][2200];
char s[1050][1050];
struct node{int xx,yy;int can;
}a[2200][2200];void B(int x,int y){for(int i=x-1,j=y-1;i>=1&&y>=1;i--,j--){if(s[i][j]!='.') break;a[i][j].can = 2;}for(int i=x+1,j=y+1;i<=n&&j<=m;i++,j++){if(s[i][j]!='.') break;a[i][j].can = 2;}for(int i=x+1,j=y-1;i<=n&&j>=1;i++,j--){if(s[i][j]!='.') break;a[i][j].can = 2;}for(int i=x-1,j=y+1;i>=1&&j<=m;i--,j++){if(s[i][j]!='.') break;a[i][j].can = 2;}
}
void K(int x,int y){int kx[8] = {-1,-1,-1,0,1,1,1,0};int ky[8] = {-1,0,1,1,1,0,-1,-1};for(int i=0;i<8;i++){if(a[x+kx[i]][y+ky[i]].can==0) a[x+kx[i]][y+ky[i]].can = 2;}
}
void R(int x,int y){for(int i=y+1;i<=m;i++){if(s[x][i]!='.') break;a[x][i].can = 2;}for(int i=y-1;i>=1;i--){if(s[x][i]!='.') break;a[x][i].can = 2;}for(int i=x+1;i<=n;i++){if(s[i][y]!='.') break;a[i][y].can = 2;}for(int i=x-1;i>=1;i--){if(s[i][y]!='.') break;a[i][y].can = 2;}
}
void P(int x,int y){if(a[x-1][y-1].can==0&&s[x-1][y-1]=='.') a[x-1][y-1].can = 2;if(a[x-1][y+1].can==0&&s[x-1][y+1]=='.') a[x-1][y+1].can = 2;
}
void Q(int x,int y){R(x , y);B(x , y);
}
void N(int x,int y){int nx[8] = {-1,-2,-2,-1,1,2,2,1};int ny[8] = {-2,-1,1,2,2,1,-1,-2};for(int i=0;i<8;i++){if(x+nx[i]<1||x+nx[i]>n||y+ny[i]<1||y+ny[i]>m) continue;if(s[x+nx[i]][y+ny[i]]!='.') continue;a[x+nx[i]][y+ny[i]].can = 2;}
}void add(int x,int y){//链式前向星建边to[++id] = y;ne[id] = head[x];head[x] = id;
}
void init(){//标记r,c数组int lenr=1;for(int i=1;i<=n+m-1;i++){for(int j=1;j<=n+m-1;j++){if(mp[i][j]==-1) continue;if(!mp[i][j]) r[i][j] = lenr;else if(mp[i][j]==1) lenr++;}lenr++;}maxx = lenr;int lenc=1;for(int i=1;i<=n+m-1;i++){for(int j=1;j<=n+m-1;j++){if(mp[j][i]==-1) continue;if(!mp[j][i]) c[j][i] = lenc;else if(mp[j][i]==1) lenc++;}lenc++;}for(int i=1;i<=n+m-1;i++){for(int j=1;j<=n+m-1;j++){if(!mp[i][j]) add(r[i][j],c[i][j]);}}
}bool dfs(int u){//匈牙利算法for(int i=head[u];i;i=ne[i]){int v = to[i];if(vis[v]) continue;vis[v] = 1;if(!d[v] || dfs(d[v])){d[v] = u;return true;}}return false;
}
int main(){scanf("%d %d",&n,&m);for (int i=1;i<=n;i++){scanf("%s",s[i]+1);}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){node f = {i+j-1 , j+n-i , a[i][j].can};if(s[i][j]=='.'){a[i][j] = f;continue;}f.can = 1;a[i][j] = f;if(s[i][j]=='B'){B(i , j);}else if(s[i][j]=='K'){K(i , j);B(i , j);}else if(s[i][j]=='R'){R(i , j);B(i , j);}else if(s[i][j]=='P'){P(i , j);B(i , j);}else if(s[i][j]=='Q'){Q(i , j);}else if(s[i][j]=='N'){N(i , j);B(i , j);}}}memset(mp,-1,sizeof(mp));for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){mp[a[i][j].xx][a[i][j].yy] = a[i][j].can; }}init();for(int i=1;i<maxx;i++){memset(vis,0,sizeof(vis));if(dfs(i)) ans++;}printf("%d\n",ans);return 0;
}

版权说明:本文为博主原创文章,转载请附上本文链接(https://blog.csdn.net/smart_CZH/article/details/125120137)。

2022-06-18 本文在洛谷用户caizehua的博客中发布。

P3882 [JLOI2008]将军 (二分图)相关推荐

  1. [JLOI2008]将军

    Description 刘先生最近在学习国际象棋,使用一个叫"jloi-08"的游戏软件.在这个游戏里,不但可以和电脑普通地对弈,还可以学习著名的棋局,还有针对初学者的规则指导等丰 ...

  2. POJ - 3041 Asteroids 二分图最小点覆盖

    题目链接 二分图一个很重要的定理:看了很多大神的博客表示看不懂为什么,以后再看 最小点覆盖=最大匹配 最小点覆盖就是在二分图里边,选择一个点,将所有与该点相链接的边删去,问最小找多少个点能够把所有的边 ...

  3. P2172 [国家集训队]部落战争 二分图最小不相交路径覆盖

    二分图最小不相交路径覆盖 #include<bits/stdc++.h> using namespace std; const int MAXN = 5550; const int MAX ...

  4. 图论:关于二分图的总结(转载)

    二分图是这样一个图,它的顶点可以分类两个集合X和Y,所有的边关联在两个顶点中,恰好一个属于集合X,另一个属于集合Y. 最大匹配:图中包含边数最多的匹配称为图的最大匹配. 完美匹配:如果所有点都在匹配边 ...

  5. c语言最小费用流_策略算法工程师之路-图优化算法(一)(二分图amp;最小费用最大流)...

    目录 1.图的基本定义 2.双边匹配问题 2.1 二分图基本概念 2.2 二分图最大匹配求解 2.3 二分图最优匹配求解 2.4 二分图最优匹配建模实例 2.4.1 二分图最优匹配在师生匹配中的应用 ...

  6. 【分布式共识三】拜占庭将军问题----书面协议

    2019独角兽企业重金招聘Python工程师标准>>> 区块链兄弟社区,区块链技术专业问答先行者,中国区块链技术爱好者聚集地 作者:吴寿鹤 来源:区块链兄弟 原文链接:http:// ...

  7. Dinic二分图匹配 || Luogu P3386

    题面:[模板]二分图匹配 思路:Dinic实现二分图匹配,要建一个超级源点(S)和超级汇点(T),分别定为N+M+1和N+M+2 然后S去和N中的数建正边和反边,正边权值为1,反边权值为0:M中的数去 ...

  8. [THUWC2017]随机二分图

    题目大意 给一张二分图,有左部点和右部点. 有三种边,第一种是直接从左部点连向右部点,出现概率为50%. 第二种边一组里有两条边,这两条边同时出现或者不出现,概率都是50%. 第三种边一组里有两条边, ...

  9. poj2289二分图多重匹配

    题意:给你一张二分图,求右边点到汇点的最小容量(保证流量为n)是多少 题解:二分答案,每次重新建边跑最大流,看是不是为n就好了 #include<map> #include<set& ...

最新文章

  1. 遇事不责怪别人,换位思考能成全更好的自己
  2. 2023 USNews全美计算机研究生院排名发布!MIT、CMU分别称霸总榜和AI分榜
  3. 关于struts2的开始学习
  4. iOS开发debug集锦
  5. c malloc 头文件_C 数据类型
  6. VTK:图表之GraphToPolyData
  7. 文献记录(part63)--跨模态社交图像聚类
  8. 每日一笑 | 如果把大脑看成CPU的话...
  9. jee过滤器应用场景_将涡轮增压器添加到JEE Apps
  10. python成绩区间曲线图_Python重现论文图表之【包含置信区间的折线柱状图】
  11. Tomcat8 安装后点击startup出现闪退的解决方法(转)
  12. net core上传文件异常:Multipart body length limit 16384 exceeded.
  13. Java循环结构语句
  14. ASAv的qcow2镜像文件添加ASDM
  15. c语言json使用,cJSON使用(二)
  16. 熵值法原理、应用及其Python实现
  17. 713页鸿蒙巨作《鸿蒙HarmonyOS手机应用开发实战》简介
  18. 云计算学习笔记1——并行计算
  19. 降噪蓝牙耳机哪款好?500元内半入耳降噪蓝牙耳机推荐
  20. 32位指针强制转换成64位数据

热门文章

  1. 生物信息学【1】:cBioPortal数据库
  2. Merriam-Webster‘s Vocabular Builder ( PROB )
  3. 集丰照明|详细解析140㎡私宅灯光设计,诠释品质生活
  4. 解决报错httpd: Could not reliably determine the server‘s fully qualified domain name
  5. 路由器使用:漫谈能上QQ不能上网问题【转】
  6. 对外SMTP(TCP25端口)发送邮件的情况处理
  7. android 实现表格横向混动_「PHEVREEV」插电混动与增程系统技术特点解析:节油原理与性能...
  8. foxmail基本操作
  9. 《深度学习进阶 自然语言处理》第六章:LSTM介绍
  10. 生活不易,未来的路还很长