ZOJ-1654 Place the Robots 拆行拆列构图+二分匹配 Or 最大独立点集+TLE
题意:给定一个方格,格子中的每点由空地,草地和墙组成,每个空地可以放置一个机器人,每个机器人能够向四个方向扫射激光,所以要给定一种方案能够在棋盘上放置足够多的机器人。激光可以穿过草地但是不能够穿过墙。
解法:这题其实就是经典的二分匹配构图题,做法是将行和列进行拆分,也即如果某一行中有一堵墙,那么将墙前面和后面视为不同的一行,对列进行同样的处理,那么每个空地就需要获得一个新的行和列属性,通过遍历整个图来给每一块空地分配一个行和列号。分配要尽可能的紧凑。对于任何一块空地,要占用一个行和一个列(意味着该行和该列内不能够再容下其他空地)对于每一块空地,将其所对应的行号和列号分为图两个部分,构成二分图。二分图中边的含义就是某一行和某一列匹配,也即一组边对应一组坐标,对应一个能够放置棋子的空地,最大匹配即为在每一行和每一列最多匹配一次的情况下最多放置多少个棋子。
采用以下方式进行编号:
行和列编号数组不小心使用char数组,段错误到崩溃......
代码如下:
#include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> using namespace std;const int MaxN = 60; int N, M, rnum, cnum; char mp[MaxN][MaxN]; int rn[MaxN][MaxN], cn[MaxN][MaxN]; // rn用来记录某一个点在拆行后的行号,同理cn用来记录某一个点在拆列后的列号void getr() { // 该函数能够为每一个空地分配拆行后的行号memset(rn, 0xff, sizeof (rn));rnum = 1;for (int i = 0; i < N; ++i) {for (int j = 0; j < M; ++j) {if (mp[i][j] == 'o') {rn[i][j] = rnum;while (++j < M && mp[i][j] != '#') {if (mp[i][j] == 'o') rn[i][j] = rnum;}// 处理位于同一行的并以空地开头的行视为一行,其中为某些草地具有连通性 --j, ++rnum;}} } }void getc() { // 该函数能够为一块空地分配一个拆列后的列号 memset(cn, 0xff, sizeof (cn));cnum = 1;for (int j = 0; j < M; ++j) {for (int i = 0; i < N; ++i) {if (mp[i][j] == 'o') {cn[i][j] = cnum;while (++i < N && mp[i][j] != '#') {if (mp[i][j] == 'o') cn[i][j] = cnum; }--i, ++cnum;}}} }char G[MaxN*MaxN][MaxN*MaxN], vis[MaxN*MaxN]; int match[MaxN*MaxN];void build() {getr();getc();memset(G, 0, sizeof (G));for (int i = 0; i < N; ++i) {for (int j = 0; j < M; ++j) {if (mp[i][j] == 'o') {G[rn[i][j]][cn[i][j]] = 1;// 一块空地占用一行和一列 }}} }bool path(int u) {for (int i = 1; i < cnum; ++i) {if (!G[u][i] || vis[i]) continue;vis[i] = 1;if (!match[i] || path(match[i])) {match[i] = u;return true;}}return false; }int query() {int ret = 0;memset(match, 0, sizeof (match));for (int i = 1; i < rnum; ++i) {memset(vis, 0, sizeof (vis));if (path(i)) {++ret;}}return ret; }/* 5 5 o***# *###* oo#oo ***#o #o**o4 */int main() {int T, ca = 0;scanf("%d", &T);while (T--) {scanf("%d %d", &N, &M);for (int i = 0; i < N; ++i) {scanf("%s", mp[i]);}printf("Case :%d\n%d\n", ++ca, (build(), query()));}return 0; }
贴个最大团TLE代码:
#include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> using namespace std;int N, M, nd[2505], idx, G[2505][2505]; char mp[55][55];bool check(int a, int b) {int x1 = nd[a]/N, y1 = nd[a]%N;int x2 = nd[b]/N, y2 = nd[b]%N;if (x1 != x2 && y1 != y2) return true;if (x1 == x2) { // 如果是在同一行for (int i = y1+1; i < y2; ++i) {if (mp[x1][i] == '#') {return true;}}}else if (y1 == y2) {for (int i = x1+1; i < x2; ++i) {if (mp[i][y1] == '#') {return true;}}}return false; }void build() {memset(G, 0, sizeof (G));for (int i = 0; i < idx; ++i) {for (int j = i+1; j < idx; ++j) {G[i][j] = G[j][i] = check(i, j);}} }int ret, cnt[2505], st[2505];void dfs(int x, int num) {for (int i = x+1; i < idx; ++i) {if (!G[x][i]) continue;if (cnt[i] + num <= ret) return;int flag = true;for (int j = 0; j < num; ++j) {if (!G[i][st[j]]) {flag = false;break;}}if (flag) {st[num] = i;dfs(i, num+1);}}if (num > ret) {ret = num;} }int query() {ret = 0;for (int i = idx-1; i >= 0; --i) {st[0] = i;dfs(i, 1);cnt[i] = ret;}return ret; }int main() {int T, ca = 0;scanf("%d", &T);while (T--) {scanf("%d %d", &N, &M);idx = 0;for (int i = 0; i < N; ++i) {scanf("%s", mp[i]);for (int j = 0; j < M; ++j) {if (mp[i][j] == 'o') {nd[idx++] = i*N+j;}}}build();printf("Case :%d\n%d\n", ++ca, query());}return 0; }
转载于:https://www.cnblogs.com/Lyush/archive/2013/04/03/2997381.html
ZOJ-1654 Place the Robots 拆行拆列构图+二分匹配 Or 最大独立点集+TLE相关推荐
- 魔百和M301A-MQ代工-非高安-S905L3芯片-当贝桌面-免拆和拆机线刷固件包
魔百和M301A-MQ代工-非高安-S905L3芯片-当贝桌面-免拆和拆机线刷固件包-内有短接点及教程 特点: 1.适用于对应型号的电视盒子刷机: 2.开放原厂固件屏蔽的市场安装和u盘安装apk: 3 ...
- 阿里中台到底拆没拆?
作者| Mr.K 整理| Emma 来源| 技术领导力(ID:jishulingdaoli) 后台一大堆读者给我留言:"老K你不是说阿里彻底拆中台了吗?怎么阿里又说要把中台建厚了?&qu ...
- 创维E900-S-非高安_HI3798MV100_免拆或拆机短接强刷-当贝桌面卡刷固件包
创维E900-S-非高安_HI3798MV100_免拆或拆机短接强刷-当贝桌面卡刷固件包 特点: 1.适用于对应型号的电视盒子刷机: 2.开放原厂固件屏蔽的市场安装和u盘安装apk: 3.修改dns, ...
- function 多个函数用一个_一列转多行多列,用INDIRECT函数,给你一个可套用的公式模板...
有一个表格,里面只有1列数据,但是有40行,为了查看可以更加方便和打印时节约纸张,现在需要将这1列数据转换成8行5列的数据,不手动复制粘贴,你有什么更好的方法解决吗? 今天,我就教大家一个方法,利用E ...
- Hive 行转列,列传行 - Impala 暂不支持
注:Impala 不支持 lateral view explode 一.行转列 (对某列拆分,一列拆多行) 使用函数:lateral view explode(split(column, ',')) ...
- SQL 行转列,列分行,行合并列(转)
/*============= ===fcuandy===== ===2008.1.23=== =============*/ CREATE TABLE ta(id INT IDENTITY(1,1) ...
- 行转列经典案例(left join)
2019独角兽企业重金招聘Python工程师标准>>> 标题或者也可改成:表自己和自己left join. 背景:最近在拆库,但是发现有个表自己和自己left join,百撕不得骑姐 ...
- Hive ,Hsql行转列、列转行实现
HQL中实现行列转换 其实并不用纠结哪个是行转列.哪个是列转行,明白二者之间的需求即可 在Hive sql应用中会遇到"行转列"和"列转行"的场景,下面介绍其基 ...
- hivesql行转列和列转行
对于行专列和列转行,有两种不同的理解,这里将两中不同的理解都整理出来,供大家参考. 1. 字段值不发生改变,只是改变行列的分布 1.1. 行转列 有如下的一张成绩表tab_scores,每个人的成绩是 ...
最新文章
- 【计算理论】可判定性 ( 通用图灵机和停机问题 | 可判定性 与 可计算性 | 语言 与 算法模型 )
- Yale CAS + .net Client 实现 SSO(3)
- 【算法】anchor free 和 anchor based 目标检测模型
- 制作一个类似苹果VFL的格式化语言来描述UIStackView
- Qt使用invokeMethod反射机制实现进程间的通信
- Kubernetes 是一个“数据库”吗?
- Python可视化:Seaborn(三)
- azure云数据库_配置Azure SQL数据库防火墙
- 10.24 环境变量PATH,cp,mv,文档查看cat/more/less/head/tail
- MOSS Search学习记录(八):高级搜索定制(中)
- 常用的HTML5和CSS3标签及用法(入门篇)
- pytorch模型预测
- 细胞分裂题--递归算法
- 文本语音阅读器——Python简单实现
- getch方法_C语言 getch()用法及代码示例
- Python编程学习视频
- google.com 打不开,但是mail.google.com无法打开,请问怎么解决?
- 【Python 实战基础】Python 中 PyQt6 的 QPen 介绍
- Java工程师必备书单
- maven-surefire-plugin