[luoguP3355] 骑士共存问题(二分图最大独立集)
模型
二分图最大独立集,转化为二分图最大匹配,从而用最大流解决。
实现
首先把棋盘黑白染色,使相邻格子颜色不同。
把所有可用的黑色格子看做二分图X集合中顶点,可用的白色格子看做Y集合顶点。
建立附加源S汇T,从S向X集合中每个顶点连接一条容量为1的有向边,从Y集合中每个顶点向T连接一条容量为1的有向边。
从每个可用的黑色格子向骑士一步能攻击到的可用的白色格子连接一条容量为无穷大的有向边。
求出网络最大流,要求的结果就是可用格子的数量减去最大流量。
分析
用网络流的方法解决棋盘上的问题,一般都要对棋盘黑白染色,使之成为一个二分图。放尽可能多的不能互相攻击的骑士,就是一个二分图最大独立集问题。有关二分图最大独立集问题,更多讨论见《最小割模型在信息学竞赛中的应用》作者胡伯涛。
该题规模比较大,需要用效率较高的网络最大流算法解决。(使用Dinic+当前弧优化)
——代码
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#define INF 1e9
#define N 1000001
#define min(x, y) ((x) < (y) ? (x) : (y)) int n, m, cnt, tot, sum, s, t;
int map[][], head[N], to[N], val[N], next[N], dis[N], cur[N];
int dx[] = {-, -, , , , , -, -},
dy[] = {, , , , -, -, -, -}; inline int read()
{
int x = , f = ;
char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -;
for(; isdigit(ch); ch = getchar()) x = (x << ) + (x << ) + ch - '';
return x * f;
} inline void add2(int x, int y, int z)
{
to[cnt] = y;
val[cnt] = z;
next[cnt] = head[x];
head[x] = cnt++;
} inline void add(int x, int y, int z)
{
add2(x, y, z);
add2(y, x, );
} inline bool bfs()
{
int i, u, v;
std::queue <int> q;
memset(dis, -, sizeof(dis));
q.push(s);
dis[s] = ;
while(!q.empty())
{
u = q.front(), q.pop();
for(i = head[u]; i ^ -; i = next[i])
{
v = to[i];
if(val[i] && dis[v] == -)
{
dis[v] = dis[u] + ;
if(v == t) return ;
q.push(v);
}
}
}
return ;
} inline int dfs(int u, int maxflow)
{
if(u == t) return maxflow;
int v, d, ret = ;
for(int &i = cur[u]; i ^ -; i = next[i])
{
v = to[i];
if(val[i] && dis[v] == dis[u] + )
{
d = dfs(v, min(val[i], maxflow - ret));
ret += d;
val[i] -= d;
val[i ^ ] += d;
if(ret == maxflow) return ret;
}
}
return ret;
} int main()
{
int i, j, k, x, y;
n = read();
m = read();
s = , t = n * n + ;
memset(head, -, sizeof(head));
for(i = ; i <= m; i++)
{
x = read();
y = read();
map[x][y] = -;
}
for(i = ; i <= n; i++)
for(j = ; j <= n; j++)
if(!map[i][j])
{
map[i][j] = ++tot;
if((i + j) & ) add(s, tot, );
else add(tot, t, );
}
for(i = ; i <= n; i++)
for(j = ; j <= n; j++)
if(map[i][j] ^ - && (i + j) & )
for(k = ; k < ; k++)
{
x = i + dx[k];
y = j + dy[k];
if(x >= && x <= n && y >= && y <= n && map[x][y] ^ -) add(map[i][j], map[x][y], INF);
}
while(bfs())
{
for(i = s; i <= t; i++) cur[i] = head[i];
sum += dfs(s, INF);
}
printf("%d\n", tot - sum);
return ;
}
[luoguP3355] 骑士共存问题(二分图最大独立集)的更多相关文章
- 洛谷P3355 骑士共存问题 二分图_网络流
Code: #include<cstdio> #include<cstring> #include<queue> #include<vector> #i ...
- 【Codevs1922】骑士共存问题(最小割,二分图最大独立集转最大匹配)
题意: 在一个n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入. 对于给定的n*n个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个 ...
- 「CODVES 1922 」骑士共存问题(二分图的最大独立集|网络流)&dinic
首先是题目链接 http://codevs.cn/problem/1922/ 结果发现题目没图(心情复杂 然后去网上扒了一张图 大概就是这样了. 如果把每个点和它可以攻击的点连一条边,那问题就变成了 ...
- Cogs 746. [网络流24题] 骑士共存(最大独立集)
[网络流24题] 骑士共存 ★★☆ 输入文件:knight.in 输出文件:knight.out 简单对比 时间限制:1 s 内存限制:128 MB 骑士共存问题 «问题描述: 在一个n*n个方格的国 ...
- COGS746. [网络流24题] 骑士共存
骑士共存问题«问题描述:在一个n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘 上某些方格设置了障碍,骑士不得进入. «编程任务:对于给定的n*n个方格的国际象棋棋盘和障碍标志 ...
- 【刷题】LOJ 6226 「网络流 24 题」骑士共存问题
题目描述 在一个 \(\text{n} \times \text{n}\) 个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入. 对于给定的 \(\t ...
- P3355 骑士共存问题
P3355 骑士共存问题 题目描述 在一个 n*n (n <= 200)个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入 对于给定的 n*n ...
- BZOJ3175:[TJOI2013]攻击装置(二分图最大独立集)
Description 给定一个01矩阵,其中你可以在0的位置放置攻击装置.每一个攻击装置(x,y)都可以按照“日”字攻击其周围的 8个位置(x-1,y-2),(x-2,y-1),(x+1,y-2), ...
- [网络流24题] 骑士共存(cogs 746)
骑士共存问题«问题描述:在一个n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘 上某些方格设置了障碍,骑士不得进入. «编程任务:对于给定的n*n个方格的国际象棋棋盘和障碍标志 ...
随机推荐
- UITableView设计思想 考察
整体使用了build模式:单是组织结构混乱:不符合人类思维. UITableViewDataSource:描述了View的要素个数情况:并担负了builder功能. UITableViewDelega ...
- C/C++基础知识:函数指针和指针函数的基本概念
[函数指针] 在程序运行中,函数代码是程序的算法指令部分,它们和数组一样也占用存储空间,都有相应的地址.可以使用指针变量指向数组的首地址,也可以使用指针变量指向函数代码的首地址,指向函数代码首地址的指 ...
- UML类图中的六种线条与六种关系
1.泛化(generalize) 实线空心三角箭头. 2.实现(realize) 虚线空心三角箭头. 3.聚合(aggregation) 实线空心菱形箭头. 4.组合(composition) 实线实 ...
- linux文件属性之linux文件删除原理
Linux是通过link的数量来控制文件删除的,只有当一个文件不存在任何link的时候,这个文件才会被删除.一般来说,每个文件都有2个link计数器:i_count和i_nlink. i_count的 ...
- setup/hold 分析
分析说明:D2:目的寄存器:D1:源寄存器: edge2:下一个时钟上升沿:edge1:当前时钟上升沿:edge0:当前时钟上升沿的前一个时钟沿:如下图: 建立时间:触发器D2(数据要到达目的的地方) ...
- 在WIN2008R2的IIS7环境下安装PHP5.6.15
1.下载PHP5.6.15 在http://windows.php.net/download页面中找到VC11 x64 Non Thread Safe下载ZIP版. 2.将下载的压缩包解压到D盘PHP ...
- 【android】签署应用采用相同证书的用处
在应用的预期生命周期内,您应使用相同证书签署所有 APK 应用升级:当系统安装应用的更新时,它会比较新版本和现有版本中的证书.如果证书匹配,则系统允许更新.如果您使用不同的证书签署新版本,则必须为应用 ...
- linux下GPIO的用户层操作(sysfs)
linux的GPIO通过sysfs为用户提供服务,下面是linux kernel里的说明文档,学习一下. GPIO Sysfs Interface for Userspace ============ ...
- python网络-Socket之TCP编程(26)
一.TCP简介 1.TCP介绍 TCP协议,传输控制协议(英语:Transmission Control Protocol,缩写为 TCP)是一种面向连接的.可靠的.基于字节流的传输层通信协议. TC ...
- GoF23种设计模式之结构型模式之享元模式
一.概述 运用共享技术有效地支持大量细粒度的对象. 二.适用性 1.当一个应用程序使用了大量的对象的时候. 2.由于使用大量的独享而造成很大的存储开销的时候. 3.对象的大多数状态都可变为外部状态的 ...