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 ...
随机推荐
- 【深圳】OSC源创会第44期 开始报名
时间:2016-03-19 14:00 地点: 深圳 南山区海德三道天利中央商务广场B座负一楼(意启创业) 费用:50元/人(现场交),女士.50积分的账号.开源软件作者.学生免费 (用于准备茶歇小食 ...
- opencv2-新特性及Mat
本文参照<opencv_2.4.9tutorial>的core部分完成.因为功力还不足以学习侯捷那种大师一样去深入浅出的解析opencv的源码,也只能先学会怎么用opencv,然后实在觉得 ...
- 使用HttpWebRequest和HtmlAgilityPack抓取网页(拒绝乱码,拒绝正则表达式)
废话不多说, 直接说需求. 公司的网站需要抓取其他网站的文章,但任务没到我这,同事搞了一下午没搞出来.由于刚刚到公司, 想证明下自己,就把活揽过来了.因为以前做过,觉得应该很简单,但当我开始做的时候, ...
- 解决nf_conntrack: table full, dropping packet问题
" > /proc/sys/net/nf_conntrack_max iptables -t raw -A PREROUTING -p tcp -m tcp --dport -j NO ...
- 备忘:hibernate, logback, slf4j实际应用一例
用hibernate写一些简单的数据库的Java应用.主要是温习一下.之前弄过的一些都忘了.发现还是得记下来,不然很快就忘. 1. Eclipse版本,用Juno, J2EE版本.最好下载zip版本的 ...
- 论文笔记Outline
1.Information publication: author: 2.What 3.Dataset 4.How input: output: method: 5.Evaluation: basel ...
- hdu2642二维树状数组单点更新+区间查询
http://acm.hdu.edu.cn/showproblem.php?pid=2642 题目大意:一个星空,二维的.上面有1000*1000的格点,每个格点上有星星在闪烁.一开始时星星全部暗淡着 ...
- 使用webpack搭建vue开发环境
最近几天项目上使用了vue.js作为一个主要的开发框架,并且为了发布的方便搭配了webpack一起使用.CSS框架使用的是vue-strap(vue 对bootstrap控件做了封装)这篇文章主要总结 ...
- [cross domain] four approachs to cross domain in javascript
four approachs can cross domain in javascript 1.jsonp 2.document.domain(only in frame and they have ...
- C#中的interface
接口(interface) 接口泛指实体把自己提供给外界的一种抽象化物(可以为另一实体),用以由内部操作分离出外部沟通方法,使其能被修改内部而不影响外界其他实体与其交互的方式. 接口实际上是一个约定: ...