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. Hibernate5笔记9--Hibernate注解式开发

    Hibernate注解式开发: (1)注解式开发的注意点: Hibernate中使用注解,主要是为了替代映射文件,完成“类到表,属性到字段”的映射.  JPA提供了一套功能强大的注解.Hibernat ...

  2. jq 判断鼠标滚动上下

    $(document).on("mousewheel DOMMouseScroll", function (e) { var delta = (e.originalEvent.wh ...

  3. Wood Cut

    Given n pieces of wood with length L[i] (integer array). Cut them into small pieces to guarantee you ...

  4. overridePendingTransition()使用

    实现两个 Activity 切换时的动画.在Activity中使用有两个参数:进入动画和出去的动画. 注意1.必须在 StartActivity()  或 finish() 之后立即调用.2.而且在 ...

  5. Python的set集合详解

    Python 还包含了一个数据类型 -- set (集合).集合是一个无序不重复元素的集.基本功能包括关系测试和消除重复元素.集合对象还支持 union(联合),intersection(交),dif ...

  6. ASP .NET Core 2.0 MVC 发布到 IIS 上以后 无法下载apk等格式的文件

    ASP .NET Core MVC 发布到  IIS 上以后 无法下载apk等格式的文件 使用.NET Core MVC创建了一个站点,其他文件可以下载,但是后来又需求,就把手机端的apk合适的文件上 ...

  7. 窗口启用/禁用功能函数EnableWindow的使用

    在非MFC环境中如何使控件或者窗口禁用呢?起初是想通过发送消息来实现,但找来找去都木有找到控件禁用的消息(也是是博主木有找到的缘故),所以只能另辟蹊径,使用 EnableWindow这个函数, 该函数 ...

  8. 链家2018春招C/C++开发实习生在线考试编程题

    题目一 题解:该题目意思就是让你输入n组数据,然后求并集,利用STL容器set集合的特性:元素不重复存储,我们可以很轻易得出答案 #include <iostream> #include ...

  9. 洛谷P3811乘法逆元

    传送门 线性递推 #include <iostream> #include <cstdio> #include <cstring> #include <alg ...

  10. 洛谷P2458 保安站岗

    传送门啦 分析: 树形dp刚刚入门,这是我做的第一个一个点同时受父亲节点和儿子节点控制的题目. 由于这个题中某一个点放不放保安与父亲和儿子都有关系(因为线段的两个端点嘛),所以我们做题时就要考虑全面. ...