P3355 骑士共存问题

题目描述

在一个 n*n (n <= 200)个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示。棋盘上某些方格设置了障碍,骑士不得进入

对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑士,使得它们彼此互不攻击

Solution

二分图最大独立集

骑士共存是这个的经典模型

两个点互相干涉的点只能取其一

定理: 二分图的最大独立集为其点数减去最大匹配数

证明:

最大独立集: 最多互不干涉的点

\(\Rightarrow\) 选出最少的点使得剩下的互不干涉

\(\Rightarrow\) 选出最多的点覆盖所有干涉边

而最小点覆盖 \(=\) 最大匹配数

故成立

证毕。

类似棋盘覆盖问题, 我们将棋盘黑白染色

发现此点与干涉点属于不同的颜色

故有干涉关系的连边做二分图最大匹配即可

此题卡匈牙利算法, 使用最大流

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define LL long long
#define REP(i, x, y) for(int i = (x);i <= (y);i++)
using namespace std;
int RD(){
int out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
const int maxn = 419, maxv = 1000019, INF = 1e9 + 19;
int head[maxn * maxn],nume = 1;
struct Node{
int v,dis,nxt;
}E[maxv << 3];
void add(int u,int v,int dis){
E[++nume].nxt = head[u];
E[nume].v = v;
E[nume].dis = dis;
head[u] = nume;
}
int len, num;
int map[maxn][maxn];
int mx[8] = {-2,-1, 1, 2, 2, 1,-1,-2};
int my[8] = {-1,-2,-2,-1, 1, 2, 2, 1};
bool judge(int x, int y){
if(x < 1 || x > len || y < 1 || y > len)return 0;
return 1;
}
int id(int x, int y){return (x - 1) * len + y;}
int s, t, maxflow;
int d[maxn * maxn];
bool bfs(){
queue<int>Q;
memset(d, 0, sizeof(d));
d[s] = 1;
Q.push(s);
while(!Q.empty()){
int u = Q.front();Q.pop();
for(int i = head[u];i;i = E[i].nxt){
int v = E[i].v;
if(!d[v] && E[i].dis){
d[v] = d[u] + 1;
Q.push(v);
if(v == t)return 1;
}
}
}
return 0;
}
int Dinic(int u, int flow){
if(u == t)return flow;
int rest = flow, k;
for(int i = head[u];i;i = E[i].nxt){
int v = E[i].v;
if(d[v] == d[u] + 1 && E[i].dis){
k = Dinic(v, min(rest, E[i].dis));
if(!k)d[v] = 0;
E[i].dis -= k;
E[i ^ 1].dis += k;
rest -= k;
if(!rest)break;
}
}
return flow - rest;
}
int main(){
len = RD(), num = RD();
s = 0, t = maxn * maxn - 19;
REP(i, 1, num){
int x = RD(), y = RD();
map[x][y] = 1;
}
REP(i, 1, len)REP(j ,1, len){
if(map[i][j])continue;
int now = id(i, j);
if((i + j) % 2 == 1)add(s, now, 1), add(now, s, 0);
else add(now, t, 1), add(t, now, 0);
}
REP(i, 1, len)REP(j ,1, len){
if(map[i][j] || (i + j) % 2 == 0)continue;
int u = id(i ,j);
for(int k = 0;k < 8;k++){
int nx = i + mx[k];
int ny = j + my[k];
if(!judge(nx, ny))continue;
if(map[nx][ny])continue;
int v = id(nx, ny);
add(u, v, 1), add(v, u, 0);
}
}
int flow = 0;
while(bfs())while(flow = Dinic(s, INF))maxflow += flow;
printf("%d\n",len * len - maxflow - num);
return 0;
}

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

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

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

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

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

  3. 洛谷P3355 骑士共存问题

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

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

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

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

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

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

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

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

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

  8. 洛谷 [P3355] 骑士共存问题

    二分图求最大独立点集 本问题在二分图中已处理过,此处用dinic写了一遍 #include <iostream> #include <cstdio> #include < ...

  9. Luogu P3355 骑士共存问题

    题目链接 \(Click\) \(Here\) 二分图最大独立集.对任意两个可以相互攻击的点,我们可以选其中一个.对于不会互相攻击的,可以全部选中.所以我们只需要求出最大匹配,根据定理,二分图最大独立 ...

随机推荐

  1. Daily Scrum (2015/10/23)

    这天晚上PM和我一起细算下来这周的确做了不少事儿.由于这天是周五,有的组员今晚有外出活动,有的组员忙了一周想休息一下.所以PM与我讨论提出今晚就布置些阅读的任务,给组员们一些自由分配的时间: 成员 今 ...

  2. Linux基础入门--04

    目录结构及文件基本操作 实验介绍: 1.Linux 的文件组织目录结构. 2.相对路径和绝对路径. 3.对文件的移动.复制.重命名.编辑等操作. 一.Linux 目录结构 在讲 Linux 目录结构之 ...

  3. Hibernate left join

    6.4.5  左外连接 左外连接(Left Outer Join)查询出左表对应的复合条件的所有记录,如查询李晓梅同学的选课信息.下面是类HQLLeftOuterJoinQuery的源代码. 其实关联 ...

  4. 9th 学习博客:使用Codebloks实现C++的图形化界面

    使用开发工具codeblocks,添加ResEdit.exe这个控件,可以很方便地进行图形化编辑,这是在网上找得教程,实现的是最基本的在对话框内添加按钮,并实现单击响应在控制台输出相应的文字. mai ...

  5. Boa服务器移植

    Boa是一种非常小巧的Web服务器,其可执行代码只有大约60KB左右.作为一种单任务Web服务器,Boa只能依次完成用户的请求,而不会fork出新的进程来处理并发连接请求.但Boa支持CGI,能够为C ...

  6. 如何处理UIVIew addsubview 不显示subview

    老代码: addsubview不显示uilabel -(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSIn ...

  7. C# 键盘记录器

    设计背景 Win系统带有API可以获取键入值,本小程序主要应用了一个网上广为流传的类,可以说一个测试DEMO.有俗称为键盘钩子 设计思路 使用Win API获取建入值 相关技术 Win API 功能 ...

  8. 【大数据】Kafka学习笔记

    第1章 Kafka概述 1.1 消息队列 (1)点对点模式(一对一,消费者主动拉取数据,消息收到后消息清除) 点对点模型通常是一个基于拉取或者轮询的消息传送模型,这种模型从队列中请求信息,而不是将消息 ...

  9. Power Strings POJ - 2406(next水的一发 || 后缀数组)

    后缀数组专题的 emm.. 就next 循环节../ 有后缀数组也可以做 从小到大枚举长度i,如果长度i的子串刚好是重复了len/i次,应该满足len % i == 0和rank[0] - rank[ ...

  10. hdu-3308 LCIS (线段树区间合并)

    LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...