P4304 [TJOI2013]攻击装置

题目描述

给定一个01矩阵,其中你可以在0的位置放置攻击装置。 每一个攻击装置(x,y)都可以按照“日”字攻击其周围的8个位置(x-1,y-2),(x-2,y-1),(x+1,y-2),(x+2,y-1),(x-1,y+2),(x-2,y+1),(x+1,y+2),(x+2,y+1)

求在装置互不攻击的情况下,最多可以放置多少个装置。

输入输出格式

输入格式:

第一行一个整数N,表示矩阵大小为N*N。

接下来N行每一行一个长度N的01串,表示矩阵。

输出格式:

一个整数,表示在装置互不攻击的情况下最多可以放置多少个装置。

输入输出样例

输入样例#1: 复制

3
010
000
100
输出样例#1: 复制

4

说明

30%数据N<=50

100%数据 N<=200


Solution

求最大点独立集,最大点独立集=点集-最大匹配

这道题因为是会相互连边,所以最后最大匹配数除以2就行了。

Code

#include<bits/stdc++.h>
using namespace std; struct Node {
int u, v, nex;
Node(int u = , int v = , int nex = ) :
u(u), v(v), nex(nex) { }
} Edge[]; int h[], stot;
void add(int u, int v) {
Edge[++stot] = Node(u, v, h[u]);
h[u] = stot;
} int n;
char s[][]; int zl[][] = {{-, -}, {-, -}, {, }, {, }, {, -}, {-, }, {-, }, {, -}};
int vis[], las[], to[], G[], id[][], t; bool dfs(int u) {
for(int i = h[u]; i; i = Edge[i].nex) {
int v = Edge[i].v;
if(vis[v] != t) {
vis[v] = t;
if(!las[v] || dfs(las[v])) {
las[v] = u; to[u] = v;
return ;
}
}
}
return ;
} bool pd(int x, int y) {
if(x < || y < || x > n || y > n || !G[id[x][y]]) return ;
return ;
} int main() {
int tot = , ans = ;
scanf("%d", &n);
for(int i = ; i <= n; i ++) scanf("%s", s[i] + );
for(int i = ; i <= n; i ++)
for(int j = ; j <= n; j ++) {
id[i][j] = (i - ) * n + j;
if(s[i][j] == '') G[id[i][j]] = , tot ++;
else G[id[i][j]] = ;
}
for(int i = ; i <= n; i ++)
for(int j = ; j <= n; j ++) {
if(!G[id[i][j]]) continue;
for(int k = ; k < ; k ++) {
int x = i + zl[k][], y = j + zl[k][];
if(!pd(x, y)) continue;
add(id[i][j], id[x][y] + n * n);
}
}
for(int i = ; i <= n * n; i ++)
if(!to[i] && G[i]) {
t ++;
ans += dfs(i);
}
printf("%d", tot - ans / );
return ;
}

P2172 [国家集训队]部落战争

题目描述

lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国的下部征战来获得更大的领土。

A国是一个M*N的矩阵,其中某些地方是城镇,某些地方是高山深涧无人居住。lanzerb把自己的部落分成若干支军队,他们约定:

  1. 每支军队可以从任意一个城镇出发,并只能从上往向下征战,不能回头。途中只能经过城镇,不能经过高山深涧。

  2. 如果某个城镇被某支军队到过,则其他军队不能再去那个城镇了。

  3. 每支军队都可以在任意一个城镇停止征战。

  4. 所有军队都很奇怪,他们走的方法有点像国际象棋中的马。不过马每次只能走1*2的路线,而他们只能走R*C的路线。

lanzerb的野心使得他的目标是统一全国,但是兵力的限制使得他们在配备人手时力不从心。假设他们每支军队都能顺利占领这支军队经过的所有城镇,请你帮lanzerb算算至少要多少支军队才能完成统一全国的大业。

输入输出格式

输入格式:

第一行包含4个整数M、N、R、C,意义见问题描述。接下来M行每行一个长度为N的字符串。如果某个字符是'.',表示这个地方是城镇;如果这个字符时'x',表示这个地方是高山深涧。

输出格式:

输出一个整数,表示最少的军队个数。

输入输出样例

输入样例#1: 复制

3 3 1 2
...
.x.
...
输出样例#1: 复制

4
输入样例#2: 复制

5 4 1 1
....
..x.
...x
....
x...
样例输出
输出样例#2: 复制

5

说明

100%的数据中,1<=M,N<=50,1<=R,C<=10。


Solution

比较轻松地可以想到最小路径覆盖问题,用最少的路径,经过所有点。

二分图是经典方法,每个点拆点,两点间有连边就在二分图上连边,最小路径=总点数-最大匹配。可以理解为,每一个匹配,就省去了一条路径(以入点为起点的路径可以由出点直接到达),所以最大匹配省去的路径是最多的。

最大匹配也可以用网络流实现。

注意空间....

Code

#include<bits/stdc++.h>
using namespace std; int G[][], n, m, r, c;
int zl[][] = {{, }, {, -}}; struct Node {
int u, v, nex;
Node(int u = , int v = , int nex = ) :
u(u), v(v), nex(nex) { }
} Edge[]; int h[], stot;
void add(int u, int v) {
Edge[++stot] = Node(u, v, h[u]);
h[u] = stot;
} bool check(int x, int y) {
if(x < || y < || x > m || y > n || !G[x][y]) return ;
return ;
} int las[], to[], vis[];
bool dfs(int u) {
for(int i = h[u]; i; i = Edge[i].nex) {
int v = Edge[i].v;
if(!vis[v]) {
vis[v] = ;
if(!las[v] || dfs(las[v])) {
to[u] = v; las[v] = u;
return ;
}
}
}
return ;
} int id[][], ans, tot;
char s[][];
int main() {
scanf("%d%d%d%d\n", &m, &n, &r, &c);
for(int i = ; i <= m; i ++) scanf("%s", s[i] + );
for(int i = ; i <= m; i ++) {
for(int j = ; j <= n; j ++) {
id[i][j] = (i - ) * n + j;
if(s[i][j] == '.') G[i][j] = , tot ++;
else G[i][j] = ;
}
}
for(int i = ; i <= m; i ++)
for(int j = ; j <= n; j ++) {
if(!G[i][j]) continue;
int x, y;
for(int k = ; k < ; k ++) {
x = i + zl[k][] * r, y = j + zl[k][] * c;
if(!check(x, y)) continue;
add(id[i][j], id[x][y] + n * m);
}
if(r != c) {
for(int k = ; k < ; k ++) {
x = i + zl[k][] * c, y = j + zl[k][] * r;
if(!check(x, y)) continue;
add(id[i][j], id[x][y] + n * m);
}
}
}
for(int i = ; i <= m; i ++) {
for(int j = ; j <= n; j ++)
if(!to[id[i][j]] && G[i][j]) {
memset(vis, , sizeof(vis));
ans += dfs(id[i][j]);
}
}
printf("%d", tot - ans);
return ;
}

【洛谷】4304:[TJOI2013]攻击装置【最大点独立集】【二分图】2172: [国家集训队]部落战争【二分图/网络流】【最小路径覆盖】的更多相关文章

  1. 洛谷P4304 [TJOI2013]攻击装置 题解

    题目链接: https://www.luogu.org/problemnew/show/P4304 分析: 最大独立集 最大独立集=总点数-最大匹配数 独立集:点集,图中选一堆点,这堆点两两之间没有连 ...

  2. 洛谷P4304 TJOI2013 攻击装置 (二分图匹配)

    题目大意:一个矩阵,一些点被拿掉,在棋盘上马走日,马之间不能落在同一点,求最多放几匹马. 采用对矩阵黑白染色,画个图可以发现:马可以走到的位置和他所处的位置颜色不同,将马和他可以走到的位置连边,最多可 ...

  3. 洛谷P2172 [国家集训队]部落战争 题解

    题目链接:https://www.luogu.org/problemnew/show/P2172 分析: 不要被[国家集训队]的标签吓到,其实这题不是很难. 本题可以对比P4304 [TJOI2013 ...

  4. 国家集训队 部落战争 网络流最小路径覆盖 洛谷P2172

    洛谷AC传送门! step1: 题目大意 有一张M x N的网格图,有一些点为“ * ”可以走,有一些点为“ x ”不能走,每走一步你都可以移动R * C 个格子(参考象棋中马的走法),且不能回头,已 ...

  5. 洛咕 P4304 [TJOI2013]攻击装置

    把坐标按照(x+y)%2染色可以发现这是个二分图 二分图最大独立集=点数-最大匹配 于是就是个算匹配的傻逼题了 // luogu-judger-enable-o2 #include<bits/s ...

  6. 洛谷P4003 [国家集训队2017]无限之环 网络流 最小费用最大流

    题意简述 有一个\(n\times m\)棋盘,棋盘上每个格子上有一个水管.水管共有\(16\)种,用一个\(4\)位二进制数来表示当前水管向上.右.下.左有个接口.你可以旋转除了\((0101)_2 ...

  7. BZOJ3175: [Tjoi2013]攻击装置

    题解: 最大点独立集...好像水过头了... 不过发现我二分图好像忘完了!!! 代码: #include<cstdio> #include<cstdlib> #include& ...

  8. BZOJ 3175: [Tjoi2013]攻击装置( 匈牙利 )

    黑白染成二分图, 然后不能同时选的就连边, 最大匹配数为m, t为不能放的数目, 则题目所求最大点独立集为 n*n-m-t -------------------------------------- ...

  9. 【BZOJ4808/3175】马/[Tjoi2013]攻击装置 最小割

    [BZOJ4808]马 Description 众所周知,马后炮是中国象棋中很厉害的一招必杀技."马走日字".本来,如果在要去的方向有别的棋子挡住(俗称"蹩马腿" ...

随机推荐

  1. 关于Java IO与NIO知识都在这里

    由于内容比较多,我下面放的一部分是我更新在我的微信公众号上的链接,微信排版比较好看,更加利于阅读.每一篇文章下面我都把文章的主要内容给列出来了,便于大家学习与回顾. Java面试通关手册(Java学习 ...

  2. Vim 快捷键整理【转】

    转自:http://blog.csdn.net/ceven2010/article/details/7406341 一.移动光标 1.左移h.右移l.下移j.上移k 2.向下翻页ctrl + f,向上 ...

  3. linux sigaction 函数 用法释义

    使用 sigaction 函数: signal 函数的使用方法简单,但并不属于 POSIX 标准,在各类 UNIX 平台上的实现不尽相同,因此其用途受 到了一定的限制.而 POSIX 标准定义的信号处 ...

  4. 编译器是如何实现32位整型的常量整数除法优化的?[C/C++]

    引子 在我之前的一篇文章[ ThoughtWorks代码挑战——FizzBuzzWhizz游戏 通用高速版(C/C++ & C#) ]里曾经提到过编译器在处理除数为常数的除法时,是有优化的,今 ...

  5. 使用gradle编译安卓APK

    一.安装JDK 在安装Gradle之前需要先安装JDK,由于安装的是Gradle是4.4所以需要安装JDK1.8. 之前编译总是提示如下错误就是由于先安装的jdk1.7然后安装的1.8造成的,在Gra ...

  6. 漂亮的SVG时钟

    漂亮的SVG时钟 效果图: 代码如下,复制即可使用: <!DOCTYPE html> <html lang="en"> <head> <m ...

  7. 多路复用IO与NIO

    最近在学习NIO相关知识,发现需要掌握的知识点非常多,当做笔记记录就下. 在学NIO之前得先去了解IO模型 (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(No ...

  8. C++之构造函数的继承

    #include<iostream> usingnamespace std; classBase1 { public: Base1()=default; Base1(const strin ...

  9. 最简单删除SQL Server中所有数据的方法(不用考虑表之间的约束条件,即主表与子表的关系)

    其实删除数据库中数据的方法并不复杂,为什么我还要多此一举呢,一是我这里介绍的是删除数据库的所有数据,因为数据之间可能形成相互约束关系,删除操作可能陷入死循环,二是这里使用了微软未正式公开的sp_MSF ...

  10. entityframework导航属性筛选

    ); //会在sql代码中生成Street = "上海"代码 var address1 = db.Entry(user).Collection(b => b.Address) ...