网络流棋盘模型 | P3355 骑士共存问题 P4304 [TJOI2013]攻击装置
题面(骑士共存问题)
在一个 \(n \times n\) 个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示。棋盘上某些方格设置了障碍,骑士不得进入。

对于给定的 \(n \times n\) 个方格的国际象棋棋盘和 \(m\) 个障碍标志,计算棋盘上最多可以放置多少个骑士,使得它们彼此互不攻击。
对于全部的测试点,保证 \(1 \leq n \leq 200\),\(0 \leq m \lt n^2\)。
思路
二分图的最大独立集。
先对这个棋盘进行黑白染色,然后发现,同颜色的格子的马永远无法互相攻击。
首先,先创立源点 \(s\),汇点 \(t\)。
然后对于白点 \((i,j)\),连边 \((s,(i,j),1)\)。对于黑点 \((k,l)\),连边 \(((k,l),t,1)\),对于可以互相攻击的点 \((a,b),(c,d)\),连边 \(((a,b),(c,d),+\infty)\)。
然后求最大独立集。
代码
P3355 骑士共存问题
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,m,s,t;
struct edge{
int from,to,val;
}e[2000001];int head[2000001],cur[2000001],siz=1;
void addedge(int x,int y,int z){
e[++siz].to=y,e[siz].val=z;
e[siz].from=head[x],head[x]=siz;
}
void add(int x,int y,int z){
addedge(x,y,z);
addedge(y,x,0);
}
int gap[2000001];
bool bfs(){
memset(gap,0,sizeof(gap));
fill(gap+1,gap+1+n,0);
queue<int> q;
q.push(s);
gap[s]=1;
while(!q.empty()){
int now=q.front();
q.pop();
for(int i=head[now];i;i=e[i].from){
int u=e[i].to;
if(e[i].val&&!gap[u]){
gap[u]=gap[now]+1;
q.push(u);
}
}
}
return (gap[t]);
}
int dfs(int now,int val){
if(now==t) return val;
for(int &i=cur[now];i;i=e[i].from){
int u=e[i].to;
if(e[i].val&&gap[now]+1==gap[u]){
int F=dfs(u,min(e[i].val,val));
if(F){
e[i].val-=F;
e[i^1].val+=F;
return F;
}
}
}
return 0;
}
int dinic(){
int ret=0;
while(bfs()){
copy(head,head+1+n,cur);
int F=0;
while(F=dfs(s,10000000000000)){
ret+=F;
}
}
return ret;
}
int knight[100000][1000];
int mk(int x,int y){
x--;
return (x*n+y);
}
int delta[][2]={{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}};
bool valid(int x){
return (x>=1)&&(x<=n);
}
signed main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
knight[x][y]=1;
}
s=0,t=n*n+1;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if((i+j)%2&&!knight[i][j]){
add(s,mk(i,j),1);
}
if(!((i+j)%2)&&!knight[i][j]){
add(mk(i,j),t,1);
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if((i+j)%2==0){
continue;
}
for(int k=0;k<8;k++){
int tx=i+delta[k][0];
int ty=j+delta[k][1];
if(valid(tx)&&valid(ty)){
if(!knight[tx][ty]){
add(mk(i,j),mk(tx,ty),INT_MAX);
}
}
}
}
}
n=n*n;
cout<<n-m-dinic()<<'\n';
return 0;
}
P4304 [TJOI2013]攻击装置
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,m,s,t;
struct edge{
int from,to,val;
}e[200001];int head[200001],cur[200001],siz=1;
void addedge(int x,int y,int z){
e[++siz].to=y,e[siz].val=z;
e[siz].from=head[x],head[x]=siz;
}
void add(int x,int y,int z){
addedge(x,y,z);
addedge(y,x,0);
}
int gap[200001];
bool bfs(){
memset(gap,0,sizeof(gap));
fill(gap+1,gap+1+n,0);
queue<int> q;
q.push(s);
gap[s]=1;
while(!q.empty()){
int now=q.front();
q.pop();
for(int i=head[now];i;i=e[i].from){
int u=e[i].to;
if(e[i].val&&!gap[u]){
gap[u]=gap[now]+1;
q.push(u);
}
}
}
return (gap[t]);
}
int dfs(int now,int val){
if(now==t) return val;
for(int &i=cur[now];i;i=e[i].from){
int u=e[i].to;
if(e[i].val&&gap[now]+1==gap[u]){
int F=dfs(u,min(e[i].val,val));
if(F){
e[i].val-=F;
e[i^1].val+=F;
return F;
}
}
}
return 0;
}
int dinic(){
int ret=0;
while(bfs()){
copy(head,head+1+n,cur);
int F=0;
while(F=dfs(s,10000000000000)){
ret+=F;
}
}
return ret;
}
int knight[10000][1000];
int mk(int x,int y){
x--;
return (x*n+y);
}
int delta[][2]={{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}};
bool valid(int x){
return (x>=1)&&(x<=n);
}
int gc(){
char ch;
do{
ch=getchar();
}while(!isdigit(ch));
return ch-'0';
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
knight[i][j]=gc();
m+=knight[i][j];
}
}
s=0,t=n*n+1;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if((i+j)%2&&!knight[i][j]){
add(s,mk(i,j),1);
}
if(!((i+j)%2)&&!knight[i][j]){
add(mk(i,j),t,1);
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if((i+j)%2==0){
continue;
}
for(int k=0;k<8;k++){
int tx=i+delta[k][0];
int ty=j+delta[k][1];
if(valid(tx)&&valid(ty)){
if(!knight[tx][ty]){
add(mk(i,j),mk(tx,ty),INT_MAX);
}
}
}
}
}
n=n*n;
cout<<n-m-dinic()<<'\n';
return 0;
}
习题:P5030 长脖子鹿放置
题面
众周所知,在西洋棋中,我们有城堡、骑士、皇后、主教和长脖子鹿。
如图所示,西洋棋的“长脖子鹿”,类似于中国象棋的马,但按照“目”字攻击,且没有中国象棋“别马腿”的规则。(因为长脖子鹿没有马腿)

给定一个\(N * M\),的棋盘,有 \(k\) 个格子禁止放棋子。问棋盘上最多能放多少个不能互相攻击的长脖子鹿。
对于\(100\)%的数据,\(1 ≤ N,M ≤ 200\)
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,m,s,t;
struct edge{
int from,to,val;
}e[2000001];int head[2000001],cur[2000001],siz=1;
void addedge(int x,int y,int z){
e[++siz].to=y,e[siz].val=z;
e[siz].from=head[x],head[x]=siz;
}
void add(int x,int y,int z){
addedge(x,y,z);
addedge(y,x,0);
}
int gap[2000001];
bool bfs(){
memset(gap,0,sizeof(gap));
fill(gap+1,gap+1+n,0);
queue<int> q;
q.push(s);
gap[s]=1;
while(!q.empty()){
int now=q.front();
q.pop();
for(int i=head[now];i;i=e[i].from){
int u=e[i].to;
if(e[i].val&&!gap[u]){
gap[u]=gap[now]+1;
q.push(u);
}
}
}
return (gap[t]);
}
int dfs(int now,int val){
if(now==t) return val;
for(int &i=cur[now];i;i=e[i].from){
int u=e[i].to;
if(e[i].val&&gap[now]+1==gap[u]){
int F=dfs(u,min(e[i].val,val));
if(F){
e[i].val-=F;
e[i^1].val+=F;
return F;
}
}
}
return 0;
}
int dinic(){
int ret=0;
while(bfs()){
copy(head,head+1+n,cur);
int F=0;
while(F=dfs(s,10000000000000)){
ret+=F;
}
}
return ret;
}
int knight[100000][1000];
int mk(int x,int y){
x--;
return (x*m+y);
}
int delta[][2]={{1,3},{1,-3},{-1,3},{-1,-3},{3,1},{3,-1},{-3,1},{-3,-1}};
bool valid(int x){
return (x>=1)&&(x<=n);
}
bool validy(int x){
return (x>=1)&&(x<=m);
}
int kkk,k;
signed main(){
cin>>n>>m>>kkk;
for(int i=1;i<=kkk;i++){
int x,y;
cin>>x>>y;
if(!knight[x][y]){
k++;
}
knight[x][y]=1;
}
s=0,t=n*m+1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if((i)%2){
add(s,mk(i,j),1);
}
if(!((i)%2)){
add(mk(i,j),t,1);
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(knight[i][j]){
continue;
}
if((i)%2==0){
continue;
}
for(int k=0;k<8;k++){
int tx=i+delta[k][0];
int ty=j+delta[k][1];
if(valid(tx)&&validy(ty)){
if(!knight[tx][ty]){
add(mk(i,j),mk(tx,ty),1);
}
}
}
}
}
n=n*m;
cout<<n-k-dinic()<<'\n';
return 0;
}
网络流棋盘模型 | P3355 骑士共存问题 P4304 [TJOI2013]攻击装置的更多相关文章
- P4304 [TJOI2013]攻击装置
传送门 看到棋盘先黑白染色冷静一下 然后发现...攻击的时候同种颜色不会相互攻击 这样就是个网络流经典套路了,关于这个套路我以前好像写过几题,那边有解释一下:传送门 #include<iostr ...
- 洛谷P4304 [TJOI2013]攻击装置 题解
题目链接: https://www.luogu.org/problemnew/show/P4304 分析: 最大独立集 最大独立集=总点数-最大匹配数 独立集:点集,图中选一堆点,这堆点两两之间没有连 ...
- 洛谷P4304 TJOI2013 攻击装置 (二分图匹配)
题目大意:一个矩阵,一些点被拿掉,在棋盘上马走日,马之间不能落在同一点,求最多放几匹马. 采用对矩阵黑白染色,画个图可以发现:马可以走到的位置和他所处的位置颜色不同,将马和他可以走到的位置连边,最多可 ...
- 洛咕 P4304 [TJOI2013]攻击装置
把坐标按照(x+y)%2染色可以发现这是个二分图 二分图最大独立集=点数-最大匹配 于是就是个算匹配的傻逼题了 // luogu-judger-enable-o2 #include<bits/s ...
- P4304 [TJOI2013]攻击装置 最小割
$ \color{#0066ff}{ 题目描述 }$ 给定一个01矩阵,其中你可以在0的位置放置攻击装置. 每一个攻击装置(x,y)都可以按照"日"字攻击其周围的8个位置(x-1, ...
- 【洛谷】4304:[TJOI2013]攻击装置【最大点独立集】【二分图】2172: [国家集训队]部落战争【二分图/网络流】【最小路径覆盖】
P4304 [TJOI2013]攻击装置 题目描述 给定一个01矩阵,其中你可以在0的位置放置攻击装置. 每一个攻击装置(x,y)都可以按照“日”字攻击其周围的8个位置(x-1,y-2),(x-2,y ...
- P3355 骑士共存问题
P3355 骑士共存问题 题目描述 在一个 n*n (n <= 200)个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入 对于给定的 n*n ...
- loj #6226. 「网络流 24 题」骑士共存问题
#6226. 「网络流 24 题」骑士共存问题 题目描述 在一个 n×n\text{n} \times \text{n}n×n 个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上 ...
- P3355 骑士共存问题 二分建图 + 当前弧优化dinic
P3355 骑士共存问题 题意: 也是一个棋盘,规则是“马”不能相互打到. 思路: 奇偶点分开,二分图建图,这道题要注意每个点可以跑八个方向,两边都可以跑,所以边 = 20 * n * n. 然后di ...
- P3355 骑士共存问题 网络流
骑士共存 题目描述 在一个 n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入 对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最 ...
随机推荐
- Mockito使用方法(Kotlin)
一.为什么要使用Mockito 1.实际案例 1.1 遇到的问题 对于经常维护的项目,经常遇到一个实际问题:需求不停改变,导致架构经常需要修改某些概念的定义. 对于某些十分基础又十分常用的概念,常常牵 ...
- 【FAQ】关于华为地图服务定位存在偏差的原因及解决办法
一. 问题描述: 华为地图服务"我的位置"能力,在中国大陆地区,向用户展示他们在地图上的当前位置与用户的实际位置存在较大的偏差. 具体差别可以查看下方的图片: 二. 偏差较大的原因 ...
- 一台虚拟机,基于docker搭建大数据HDP集群
前言 好多人问我,这种基于大数据平台的xxxx的毕业设计要怎么做.这个可以参考之前写得关于我大数据毕业设计的文章.这篇文章是将对之前的毕设进行优化. 个人觉得可以分为两个部分.第一个部分就是基础的平台 ...
- iphoneApp Fidder设置
使用iphone 打开fidder 按照如上配置 安装完毕 然后访问计算机地址- 比如我的计算机ip地址是 192.168.2.10那么我需要在我的safari浏览器中输入192.168.2.10:8 ...
- 开源项目在线化 中文繁简体转换/敏感词/拼音/分词/汉字相似度/markdown 目录
前言 以前在 github 上自己开源了一些项目.碍于技术与精力,大部分项目都是 java 实现的. 这对于非 java 开发者而言很不友好,对于不会编程的用户更加不友好. 为了让更多的人可以使用到这 ...
- webpack -- element-ui 的按需引入
简单说明原理: 使用babel-plugin-component实现按需引入.打包.将webpack配置成多入口,保证最终打包的目录结构符合babel-plugin-component插件的要求,实现 ...
- PHP实现CURL发送请求
public function curl($url, $params = false, $ispost = 0) { $httpInfo = array(); //初始化 $ch = curl_ini ...
- Go语言核心36讲38
到目前为止,我们已经一起陆陆续续地学完了Go语言中那些最重要也最有特色的概念.语法和编程方式.我对于它们非常喜爱,简直可以用如数家珍来形容了. 在开始今天的内容之前,我先来做一个简单的总结. Go语言 ...
- PLSql在Oracle中创建表空间
create tablespace db_test --表空间名 datafile 'D:\oracle\product\11.2.0\dbhome_1\oradata\orcl\test.dbf' ...
- JavaEE Day05 JDBC(用Java语言操作数据库)
今日内容 基本概念 快速入门 对JDBC中各个接口和类的详解 一.基本概念 1.概念:Java Database Connectivity:Java数据库连接,Java语言操作数据库 2.本质:官方( ...