HDU 5925 Coconuts
2016 CCPC 东北四省赛 D.
一道好题.
现场写崩了.
赛后LSh跟我讲了一种离散化的做法, 没听懂.
题意
一个$R \cdot C\ (R, C\le 10^9)$ 的矩形点阵上有 $n \ (n \le 200) $ 个坏点, 其余都是好点.
求好点的4-连通块 (以下简称cell) 的个数和每块的大小.
做法
我的想法是:
找出一个坏点的8-连通块, 在框住这个块的(最小)矩形区域内, 搜索当前8-连通块以及整个矩形点阵的边界 (以下简称"fence") 包围的cell.
这个想法大体上没什么漏洞.
要注意的问题有
- fence 套 fence 的情况
- 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数组+全局变量
一个好点的连通块合法的条件:
- 不超出矩形框
- 至少能遇到一个当前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的更多相关文章
- HDU 5925 Coconuts 离散化
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5925 Coconuts Time Limit: 9000/4500 MS (Java/Others) ...
- HDU 5925 Coconuts 【离散化+BFS】 (2016CCPC东北地区大学生程序设计竞赛)
Coconuts Time Limit: 9000/4500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Su ...
- hdu 5925 Coconuts 离散化+dfs
Coconuts Time Limit: 9000/4500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem ...
- Coconuts HDU - 5925 (二维离散化求连通块的个数以及大小)
题目链接: D - Coconuts HDU - 5925 题目大意:首先是T组测试样例,然后给你n*m的矩阵,原先矩阵里面都是白色的点,然后再输入k个黑色的点.这k个黑色的点可能会使得原先白色的点 ...
- Coconuts HDU - 5925 二维离散化 自闭了
TanBig, a friend of Mr. Frog, likes eating very much, so he always has dreams about eating. One day, ...
- HDU 5925 离散化
东北赛的一道二等奖题 当时学长想了一个dfs的解法并且通过了 那时自己也有一个bfs的解法没有拿出来 一直没有机会和时ji间xing来验证对错 昨天和队友谈离散化的时候想到了 于是用当时的思路做了一下 ...
- 2016 长春东北赛---Coconuts(离散化+DFS)
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5925 Problem Description TanBig, a friend of Mr. Frog ...
- HDU 5929 Basic Data Structure 【模拟】 (2016CCPC东北地区大学生程序设计竞赛)
Basic Data Structure Time Limit: 7000/3500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Oth ...
- HDOJ 2111. Saving HDU 贪心 结构体排序
Saving HDU Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
随机推荐
- TinyFrame再续篇:整合Spring AOP实现日志拦截
上一篇中主要讲解了如何使用Spring IOC实现依赖注入的.但是操作的时候,有个很明显的问题没有解决,就是日志记录问题.如果手动添加,上百个上千个操作,每个操作都要写一遍WriteLog方法,工作量 ...
- Python.Django视频教程(全13集)
Python.Django视频教程(全13集)教程目录: 下载地址:http://www.fu83.cn/thread-205-1-1.html
- Eclipse工作常见问题总结
一.Eclipse常见快捷键使用 自动完成单词:Alt+/ 重命名:Shift+Alt+r(统一改变字段或方法名) 生成getter/setter方法: Shift+Alt+s,然后r 删除当前行:C ...
- JavaScript的一些知识碎片(1)
打算把使用Javascript的水平从child提升到小学毕业,近期会持续记录一些知识点. javascript的引用机制:只要一个对象赋值为另一个对象,就建立了引用.一旦建立了引用,对象们就公用一块 ...
- Windows下搭建PHP环境:Apache+PHP+MySQL
本文简单记录一下Windows下搭建PHP环境的过程,一些细节可以参照本文参考资料,此文不再赘述 准备工作: Windows下手工搭建PHP环境需要先下载相应的软件,需要注意的是Apache与PHP的 ...
- 此utf8 非彼utf8 ——谈http协议里的编码问题
我这里看两个编码: BDPAGETYPE:2BDQID:0xc92b034d0bc985e8BDUSERID:809441751 Cache-Control:private Connection:Ke ...
- Sql 2012 远程数据库连接
新装好的数据库,各种远程连接设置都设置好后.发现还是连接不上. 这时候,问题可能出在端口上,远程连接的时候需要指明端口.动态端口一般都会变.在本机连接时候,会自动选择端口.在远程访问时候,就必须要指明 ...
- KM模板
var n,m,i,j:longint; ans:int64; sel,lx,ly,slack:..] of int64; a:..,..] of int64; visx,visy:..] of bo ...
- N-gram模型
n元语法 n-gram grammar 建立在马尔可夫模型上的一种概率语法.它通过对自然语言的符号串中n个符号同时出现概率的统计数据来推断句子的结构关系.当n=2时,称为二元语法,当 ...
- 网页设计:Meta标签详解
很多人忽视了HTML标签META的强大功效,一个好的META标签设计可以大大提高你的个人网站被搜索到的可能性,有兴趣吗,谁我来重新认识一下META标签吧! META标签是HTML语言HEAD区的一个辅 ...