2016 CCPC 东北四省赛 D.

一道好题.

现场写崩了.

赛后LSh跟我讲了一种离散化的做法, 没听懂.

题意

一个$R \cdot C\ (R, C\le 10^9)$ 的矩形点阵上有 $n \ (n \le 200) $ 个坏点, 其余都是好点.

好点的4-连通块 (以下简称cell) 的个数和每块的大小.

做法

我的想法是:

找出一个坏点的8-连通块, 在框住这个块的(最小)矩形区域内, 搜索当前8-连通块以及整个矩形点阵的边界 (以下简称"fence") 包围的cell.

这个想法大体上没什么漏洞.

要注意的问题有

  1. fence 套 fence 的情况
  2. dfs的各种边界情况的顺序 (我是用dfs搜索好点的4-连通块的)

对于fence 套 fence 的情况, 如果对两个fence不加区分 就会导致重复统计.

Solution: 对每个 (可能的) fence 上的坏点编号.

实现上的坑

这题的坑真多 (至少对蒟蒻我而言如此)

一开始核心代码是这样写的:

int dx[]{-1, 1, 0, 0}, dy[]{0, 0, 1, -1};

bool used[205][205];

int dfs(int _x, int _y){
if(_x==0 || _x==r+1 || _y==0 || _y==c+1){
return -2;
} for(int i=0; i<n; i++){
if(_x==x[i] && _y == y[i]){
return vis[i]==id?0:-3;
}
}
// good nut
if(_x<x1 || _x > x2 || _y < Y1 || _y > y2){
return -1;
} if(used[_x-x1][_y-Y1]){
return 0;
} used[_x-x1][_y-Y1]=true;
int res=0; bool flag=false; for(int i=0; i<4; i++){
int nx=_x+dx[i], ny=_y+dy[i];
int tmp = dfs(nx, ny); if(tmp == -1){
return -1;
} else if(tmp>=0) flag=true; else if(tmp>0) res+=tmp;
} return flag?res+1:0;
}

这个dfs的目的是搜索好点的4-连通块, 同时判断该连通块是否合法.

然而我这种用返回值判断合法性的dfs写法却隐藏着一个bug:

注意dfs中的这样一段代码:

for(int i=0; i<4; i++){
int nx=_x+dx[i], ny=_y+dy[i];
int tmp = dfs(nx, ny); if(tmp == -1){
return -1;
} else if(tmp>=0) flag=true; else if(tmp>0) res+=tmp;
}

其中的

if(tmp == -1){
return -1;
}

当dfs到一个超出当前矩形框的点时, 就会返回-1.

这样的写法在某些情况下会让好点也成为fence的一部分, 从而无法搜出一个好点的4-连通块. (这一点还会详谈)

比较好的写法:

vis数组+全局变量

一个好点的连通块合法的条件:

  1. 不超出矩形框
  2. 至少能遇到一个当前fence上的坏点

我们用两个全局的bool值 (flag) 来表示这两个条件是否成立, 再用一个全局变量记录当前连通块的大小.

Implementation

#include <bits/stdc++.h>
using namespace std; const int N=205; int x[N], y[N];
int vis[N]; // vector<int> st; int r, c, n; int x1, x2, Y1, y2;
int id; void dfs(int i){
// st.push_back(i);
vis[i]=id;
x1=min(x1, x[i]);
x2=max(x2, x[i]);
Y1=min(Y1, y[i]);
y2=max(y2, y[i]); for(int dx=-1; dx<=1; dx++)
for(int dy=-1; dy<=1; dy++){
int nx=x[i]+dx, ny=y[i]+dy;
for(int j=0; j<n; j++){
if(!vis[j] && x[j]==nx && y[j]==ny){
dfs(j);
break; // ?
}
}
}
} int dx[]{-1, 1, 0, 0}, dy[]{0, 0, 1, -1}; bool used[205][205];
bool f1, f2;
int cnt; void dfs(int _x, int _y){
// on border
if(_x==0 || _x==r+1 || _y==0 || _y==c+1){
return;
}
// out of range
if(_x<x1 || _x > x2 || _y < Y1 || _y > y2){
f1=false;
return;
}
// bad nut
for(int i=0; i<n; i++){
if(_x==x[i] && _y == y[i]){
if(vis[i]==id)
f2=true;
return;
}
} // good nut
if(used[_x-x1][_y-Y1]){
return;
}
// cout<<_x<<' '<<_y<<endl;
used[_x-x1][_y-Y1]=true;
++cnt; for(int i=0; i<4; i++){
int nx=_x+dx[i], ny=_y+dy[i];
dfs(nx, ny);
}
} vector<long long> res;
long long tot; void clac(){
for(int i=x1; i<=x2; i++)
for(int j=Y1; j<=y2; j++){
used[i-x1][j-Y1]=false;
} for(int i=x1; i<=x2; i++)
for(int j=Y1; j<=y2; j++){
f1=true, f2=false;
cnt=0;
dfs(i, j);
// cout<<cnt<<endl;
// if(f1) puts("f1");
// if(f2) puts("f2");
if(f1 && f2 && cnt>0){
tot-=cnt;
res.push_back(cnt);
}
}
} void solve(int n){
res.clear();
for(int i=0; i<n; i++){
vis[i]=0;
} tot=(long long)r*c-n;
id=0; for(int i=0; i<n; i++){
if(!vis[i]){
x1=Y1=INT_MAX;
x2=y2=INT_MIN;
++id;
dfs(i);
clac();
}
} if(tot>0) res.push_back(tot); sort(res.begin(), res.end());
printf("%lu\n", res.size()); for(size_t i=0; i<res.size(); i++){
if(i) putchar(' ');
printf("%lld", res[i]);
} puts("");
} int main(){
int T, cas=0;
for(cin>>T; T--; ){
printf("Case #%d:\n", ++cas); cin>>r>>c>>n; for(int i=0; i<n; i++){
scanf("%d%d", x+i, y+i);
}
solve(n);
}
return 0;
}

另外一个更隐蔽的坑:

DFS 的三个边界情况 (点阵边界, 超出矩形框, 坏点) 的顺序.

HDU 5925 Coconuts的更多相关文章

  1. HDU 5925 Coconuts 离散化

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5925 Coconuts Time Limit: 9000/4500 MS (Java/Others) ...

  2. HDU 5925 Coconuts 【离散化+BFS】 (2016CCPC东北地区大学生程序设计竞赛)

    Coconuts Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Su ...

  3. hdu 5925 Coconuts 离散化+dfs

    Coconuts Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem ...

  4. Coconuts HDU - 5925 (二维离散化求连通块的个数以及大小)

    题目链接: D - Coconuts  HDU - 5925 题目大意:首先是T组测试样例,然后给你n*m的矩阵,原先矩阵里面都是白色的点,然后再输入k个黑色的点.这k个黑色的点可能会使得原先白色的点 ...

  5. Coconuts HDU - 5925 二维离散化 自闭了

    TanBig, a friend of Mr. Frog, likes eating very much, so he always has dreams about eating. One day, ...

  6. HDU 5925 离散化

    东北赛的一道二等奖题 当时学长想了一个dfs的解法并且通过了 那时自己也有一个bfs的解法没有拿出来 一直没有机会和时ji间xing来验证对错 昨天和队友谈离散化的时候想到了 于是用当时的思路做了一下 ...

  7. 2016 长春东北赛---Coconuts(离散化+DFS)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5925 Problem Description TanBig, a friend of Mr. Frog ...

  8. HDU 5929 Basic Data Structure 【模拟】 (2016CCPC东北地区大学生程序设计竞赛)

    Basic Data Structure Time Limit: 7000/3500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Oth ...

  9. HDOJ 2111. Saving HDU 贪心 结构体排序

    Saving HDU Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

随机推荐

  1. warning: #870-D: invalid multibyte character sequence

    warning: #870-D: invalid multibyte character sequence2011-03-12 9:18warning: #870-D: invalid multiby ...

  2. Java 位运算(移位、位与、或、异或、非)

    Java提供的位运算符有:左移( << ).右移( >> ) .无符号右移( >>> ) .位与( & ) .位或( | ).位非( ~ ).位异或( ...

  3. des解密不完整,前面几位是乱码的解决办法

    在工作中遇到的Des解密问题,第三方发来的数据需要我们进行des解密,但是解密的结果前几位始终是乱码.废了半天劲,终于找到了问题所在. 下面先介绍一下des,了解des的同学可以直接看下面的解决办法. ...

  4. 千呼万唤岂出来,写款软件不容易——Visual Entity 2.0 发布

    在各位用户不继的催更中,终于完成了这次更新.Visual Entity这个软件发布于 2011年,这个软件完成后,便上班去了,也没有做什么推广工作.所以知道的用户并不多,尽管它是个非常好用.并且免费的 ...

  5. C语言文件的读写

    对文件的读和写是最常用的文件操作.在C语言中提供了多种文件读写的函数: 字符读写函数  :fgetc和fputc 字符串读写函数:fgets和fputs 数据块读写函数:freed和fwrite 格式 ...

  6. RHCE实验环境|rhel7-lab

    教学环境说明: 1.yum源地址是:http://content.example.com 2.网卡都用同一个,且自定义网卡! 3.网络配置参考 classroom IP 172.25.254.254/ ...

  7. C# 面试的“区别”

    1.静态变量与非静态变量的区别 静态变量--static.直接类名+变量名.静态函数里不能用非静态变量. 访问同一类中所有实例同一静态变量都是同一值.非静态变量则不是. 2.const与readonl ...

  8. Keepalived+Redis高可用部署(第二版)

    更新 20150625 脚本由5个减少为4个,sh脚本指令做了精简. 修改了另外3个脚本,在日志里增加了日期显示. 新增redis数据类型,持久化,主从同步简介. 新增hiredis简介. 新增c语言 ...

  9. android 按钮点击效果实现 在studio下出现的错误

    在照做上一篇随笔的时候 在studio下为了方便我在写完一个 btn_select.xml 文件后直接粘贴了三个文件到drawable下 结果问题来了 总是报这样一个错误: Resource is n ...

  10. Beta冲刺---Day2

    站立式会议 站立式会议内容总结: 221: 昨日完成: 1.这几天的安排,接口测试. 今天要完成: 1.协作编写系负责人审核 遇到问题: 1.无 328: 昨天完成的事情: 1.无 今天要完成的事情: ...