题目链接:P3355 骑士共存问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题解:

棋盘问题考虑黑白染色成为二分图后做。

观察马的性质,可知一个点只能到一个异色点,所以,构造方案可以先将所有同色点放上马,再考虑有那些异色点不可以放置。

方法一:

网络流,时间复杂度为O(|E|min(|E|0.5,|V|0.3))

从源点向每个白点连一条限制为1的边(黑色,白色都可以我选定先在白色放满马)(这里的1没有太大的意义,可以理解为每个点一匹马)

从白点向与它不可共存的点,连边,限制为1因为流量最大为1。

从黑点向汇点连一条限制为1的边。

最后答案为n*n-m-ans,表示总点数减去障碍点,再减去冲突的黑点。

#include <bits/stdc++.h>
using namespace std;
const int N=50010;
const int M=500010;
int tot=1,n,m,s,t,nxt[M],go[M],hd[N],dep[N],cur[N],vis[N],jz[M],ans;
queue<int> q;
bool bfs()
{
memset(dep,0,sizeof(dep));
memcpy(cur,hd,sizeof(hd));
q.push(s);
dep[s]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=hd[u];i;i=nxt[i])
{
int v=go[i];
if(!jz[i]||dep[v])continue;
dep[v]=dep[u]+1;
q.push(v);
}
}
return dep[t];
}
int dfs(int u,int flow)
{
if(u==t)return flow;
int out=0;
for(int i=cur[u];i&&flow;i=nxt[i])
{
cur[u]=i;
int v=go[i];
if(jz[i]&&dep[v]==dep[u]+1)
{
int res=dfs(v,min(jz[i],flow));
if(res)
{
jz[i]-=res;jz[i^1]+=res;flow-=res;out+=res;
}
}
}
if(out==0) dep[u]=0;
return out;
}
void add(int u,int v,int w)
{
nxt[++tot]=hd[u];
hd[u]=tot;
go[tot]=v;
jz[tot]=w;
}
int id(int x,int y)
{
return (x-1)*n+y;
}
int xj[10]={2,2,-2,-2,1,1,-1,-1};
int yj[10]={1,-1,1,-1,2,-2,2,-2};
int main()
{
scanf("%d%d",&n,&m);
s=0,t=n*n+1;
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
vis[id(x,y)]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int ids=id(i,j);
if(vis[ids])continue;
if((i+j)%2==0)
{
add(s,ids,1);
add(ids,s,0);
for(int k=0;k<8;k++)
{
int x=i+xj[k];
int y=j+yj[k];
if(x>0&&y>0&&x<=n&&y<=n&&vis[id(x,y)]==0)
{
add(ids,id(x,y),1e9);
add(id(x,y),ids,0);
}
}
}
else
{
add(ids,t,1);
add(t,ids,0);
}
}
while(bfs())
ans+=dfs(s,1e9);
printf("%lld\n",n*n-m-ans);
return 0;
}

方法二:
匈牙利算法。

从白点向限制的黑点连边,跑匈牙利,求最大匹配。

但是加了一个数据,匈牙利跑不过去,所以二分图的问题,最好转成网络流来做,更快。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=50010;
const int M=500010;
int tot,n,m,nxt[M],go[M],hd[N],girl[N],ans,wz[210][210];
bool bk[N],vis[N];
int xj[10]={2,2,-2,-2,1,1,-1,-1};
int yj[10]={1,-1,1,-1,2,-2,2,-2};
inline int read(){
int ans=0;char c;bool flag=true;
for(;c<'0'||c>'9';c=getchar())if(c=='-')flag=false;
for(;c>='0'&&c<='9';c=getchar())ans=ans*10+c-'0';
return flag ? ans : -ans;
}
inline void add(int x,int y)
{
nxt[++tot]=hd[x];go[tot]=y;hd[x]=tot;
return ;
}
inline bool find(int x)
{
for(int i=hd[x];i;i=nxt[i])
{
int y=go[i];
if(vis[y])continue;
vis[y]=1;
if(!girl[y]||find(girl[y]))
{
girl[y]=x;
return 1;
}
}
return 0;
}
inline int id(int x,int y)
{
return (x-1)*n+y;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=m;i++)
{
int x,y;
x=read(),y=read();
bk[id(x,y)]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
wz[i][j]=id(i,j);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(bk[wz[i][j]])continue;
if((i+j)%2)
for(int k=0;k<8;k++)
{
int x=i+xj[k];
int y=j+yj[k];
if(x>0&&y>0&&x<=n&&y<=n&&bk[wz[x][y]]==0)
add(wz[i][j],wz[x][y]);
} }
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if((i+j)%2&&!bk[wz[i][j]])
{
memset(vis,0,sizeof(vis));
if(find(wz[i][j]))ans++;
}
printf("%d\n",n*n-m-ans);
return 0;
}

    

P3355 骑士共存问题题解的更多相关文章

  1. P3355 骑士共存问题

    P3355 骑士共存问题 题目描述 在一个 n*n (n <= 200)个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入 对于给定的 n*n ...

  2. P3355 骑士共存问题 二分建图 + 当前弧优化dinic

    P3355 骑士共存问题 题意: 也是一个棋盘,规则是“马”不能相互打到. 思路: 奇偶点分开,二分图建图,这道题要注意每个点可以跑八个方向,两边都可以跑,所以边 = 20 * n * n. 然后di ...

  3. 网络流棋盘模型 | P3355 骑士共存问题 P4304 [TJOI2013]攻击装置

    题面(骑士共存问题) 在一个 \(n \times n\) 个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入. 对于给定的 \(n \times n ...

  4. P3355 骑士共存问题 网络流

    骑士共存 题目描述 在一个 n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入 对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最 ...

  5. 洛谷P3355 骑士共存问题

    题目描述 在一个 n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入 对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置 ...

  6. P3355 骑士共存问题【洛谷】(二分图最大独立集变形题) //链接矩阵存图

    展开 题目描述 在一个 n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入 对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可 ...

  7. 2018.08.02 洛谷P3355 骑士共存问题(最小割)

    传送门 这题让我联想到一道叫做方格取数问题的题,如果想使摆的更多,就要使不能摆的更少,因此根据骑士的限制条件建图,求出至少有多少骑士不能摆,减一减就行了. 代码: #include<bits/s ...

  8. 【Luogu】P3355骑士共存问题(最小割)

    题目链接 像题面那样把棋盘染成红黄点.发现骑士迈一步能到达的点的颜色一定是跟他所在的格子的颜色不同的.于是(woc哪来的于是?这个性质有这么明显吗?)从源点向所有红点连边,从所有黄点向汇点连边,红点向 ...

  9. LUOGU P3355 骑士共存问题(二分图最大独立集)

    传送门 因为骑士只能走"日"字,所以一定是从一个奇点到偶点或偶点到奇点,那么这就是一张二分图,题目要求的其实就是二分图的最大独立集.最大独立集=n-最大匹配. #include&l ...

  10. P3355 骑士共存问题 (最小割)

    题意:nxn的棋盘 有m个坏点 求能在棋盘上放多少个马不会互相攻击 题解:这个题仔细想想居然和方格取数是一样的!!! 每个马他能攻击到的地方的坐标 (x+y)奇偶性不一样 于是就黑白染色 s-> ...

随机推荐

  1. 六:大数据架构 - Flink + AI

    Flink 在AI 中的价值其实和大数据Lambda架构中流批统一这两个概念有关系,Flink为大数据实时化带来的价值也将同样使AI受益 大数据的发展过程 从Google奠基性的"三架马车& ...

  2. 显示器AVG、DVI、HDMI、DisplayPort、Type-C、雷电接口

    在近十年的发展,显示设备的接口发生了巨大的改变.以前使用比较多的是蓝色VGA接口,接著出现了白色的DVI接口,当遇到不同接口时,还得买转接头进行转接.后来,又有了HDMI等接口,现在则出现DP和USB ...

  3. 一图明白ACHI,SATA之间的关系

    从上图中可以看到,SATA与PCI-E不仅可以指代物理的接口,还可以指代物理接口使用的传输协议. M.2物理接口可以使用SATA.PCI-E传输协议. U.2可以使用PCI-E传输协议.在网上搜了一下 ...

  4. ansible系列(24)--ansible的loop循环语句

    目录 1. loop循环语句 1.1 使用循环批量安装软件 1.2 使用循环批量启动服务 1.3 使用循环批量创建用户 1.4 使用循环批量拷贝文件 1. loop循环语句 在写 playbook 的 ...

  5. 推荐一款微信公众平台Python开发神器!

    1.引言 在当今数字化时代,微信公众平台成为了企业和个人连接用户的重要渠道.为了高效地管理和与用户互动,开发者需要一个强大而灵活的工具. Weixin-Python 正是这样一个为微信公众平台量身打造 ...

  6. 构建自定义镜像并优化dockerfile文件

    目录 一.系统环境 二.前言 三.镜像构建步骤 四.dockerfile文件常用指令 4.1 dockerfile文件常用指令 4.2 RUN.CMD.ENTRYPOINT的区别 五.构建centos ...

  7. Windows系统命令行的最佳实践

    更多博文请关注:https://blog.bigcoder.cn 每次看到Mac生态中炫酷的命令行工具,我就一脸羡慕,但是奈何财力不足,整不起动辄上万的电脑,搬砖人就只能折腾折腾手里的这台window ...

  8. mp4封装格式与MPEG4Extractor

    首先来看mp4的封装格式,mp4数据都被放在一个个的箱子当中,也就是box,box的字节序为网络字节序,也就是大端存储,box由header和body组成,header指明box的大小和类型,body ...

  9. C# wpf之控制屏幕显示方向旋转

    using System;using System.Collections.Generic;using System.Linq;using System.Runtime.InteropServices ...

  10. 智影AI故事转视频创作神器!快速开启AI绘画小说推文之旅

    1.前言 1.1 生成内容形式 生成内容形式主要包含三种,PGC(Professionally Generated Content).UGC(User Generated Content).AIGC( ...