P3355 骑士共存问题题解
题目链接: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 骑士共存问题题解的更多相关文章
- P3355 骑士共存问题
P3355 骑士共存问题 题目描述 在一个 n*n (n <= 200)个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入 对于给定的 n*n ...
- P3355 骑士共存问题 二分建图 + 当前弧优化dinic
P3355 骑士共存问题 题意: 也是一个棋盘,规则是“马”不能相互打到. 思路: 奇偶点分开,二分图建图,这道题要注意每个点可以跑八个方向,两边都可以跑,所以边 = 20 * n * n. 然后di ...
- 网络流棋盘模型 | P3355 骑士共存问题 P4304 [TJOI2013]攻击装置
题面(骑士共存问题) 在一个 \(n \times n\) 个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入. 对于给定的 \(n \times n ...
- P3355 骑士共存问题 网络流
骑士共存 题目描述 在一个 n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入 对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最 ...
- 洛谷P3355 骑士共存问题
题目描述 在一个 n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入 对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置 ...
- P3355 骑士共存问题【洛谷】(二分图最大独立集变形题) //链接矩阵存图
展开 题目描述 在一个 n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入 对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可 ...
- 2018.08.02 洛谷P3355 骑士共存问题(最小割)
传送门 这题让我联想到一道叫做方格取数问题的题,如果想使摆的更多,就要使不能摆的更少,因此根据骑士的限制条件建图,求出至少有多少骑士不能摆,减一减就行了. 代码: #include<bits/s ...
- 【Luogu】P3355骑士共存问题(最小割)
题目链接 像题面那样把棋盘染成红黄点.发现骑士迈一步能到达的点的颜色一定是跟他所在的格子的颜色不同的.于是(woc哪来的于是?这个性质有这么明显吗?)从源点向所有红点连边,从所有黄点向汇点连边,红点向 ...
- LUOGU P3355 骑士共存问题(二分图最大独立集)
传送门 因为骑士只能走"日"字,所以一定是从一个奇点到偶点或偶点到奇点,那么这就是一张二分图,题目要求的其实就是二分图的最大独立集.最大独立集=n-最大匹配. #include&l ...
- P3355 骑士共存问题 (最小割)
题意:nxn的棋盘 有m个坏点 求能在棋盘上放多少个马不会互相攻击 题解:这个题仔细想想居然和方格取数是一样的!!! 每个马他能攻击到的地方的坐标 (x+y)奇偶性不一样 于是就黑白染色 s-> ...
随机推荐
- U.2与M.2接口
U.2接口 U.2接口别称SFF-8639,是由固态硬盘形态工作组(SSD Factor Work Group)推出的接口规范.U.2接口不但能支持SATA-Express(一种PCI-E与SATA混 ...
- Atera 用户为最终用户提供对办公计算机的远程访问
一言以蔽之:由 Splashtop 提供支持的 Atera 的客户远程访问功能允许使用 Atera 的 MSP 设置和管理其最终用户对办公计算机的远程访问. 新冠肺炎大流行已加速了全球远程工作的进程 ...
- 当字符遇上 scanf() 要当心
当字符遇上 scanf() 要当心 看一下程序 char ch1,ch2; printf("请输入ch1,ch2的值:"); scanf("%c %c",&am ...
- 万事通,专精部分领域的多功能 Transformer 智能体
介绍 我们很高兴分享"万事通"(Jack of All Trades,简称 JAT) 项目,该项目旨在朝着通用智能体的方向发展.该项目最初是作为对 Gato (Reed 等,202 ...
- 80x86汇编—80x86架构
文章目录 计算机如何工作 存储器 逻辑地址到物理地址 寄存器 数据寄存器使用细节 其他知识点细节 堆栈Stack 标志寄存器 中断 汇编入门简单,深入难 使用8086架构进行学习,本章节如果没有学过计 ...
- .net core DataTable.Load()方法,返回的行缺少,少于reader读出的行
我分析的原因是,datatable模式的schema默认是根据查询的sql来的.起因是我写的sql中带有主键的列,查出来有很多重复值, 然后dt.load会默认把主键重复的行给合并掉,所以最终查询出来 ...
- Swoole 源码分析之 Coroutine 协程模块
首发原文链接:Swoole 源码分析之 Coroutine 协程模块 大家好,我是码农先森. 引言 协程又称轻量级线程,但与线程不同的是:协程是用户级线程,不需要操作系统参与.由用户显式控制,可以在需 ...
- js 中你不知道的各种循环测速
在前端 js 中,有着多种数组循环的方式: for 循环: while 和 do-while 循环: forEach.map.reduce.filter 循环: for-of 循环: for-in 循 ...
- go append的坑
b := []int{1,2,3,4,5} slice := b[:2] newSlice := append(slice, 50) fmt.Println(b) fmt.Println(newSli ...
- RDP 端口转发 多窗口运行
需要设置本机的默认端口进行修改 优点:(1)部署简单.Windows自带,支持IPv4和IPv6(2)不用重启机器,还长记性.命令即时生效,重启系统后配置仍然存在.缺点:(1)不支持UDP(2)XP/ ...