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. 一次莽撞的行为:在phpmyadmin中修改MySQL root密码后无法操作数据库

    一.手贱行为(✿◡‿◡) 在一次开发中通过xampp方式安装了PHP环境,需要操作数据库时通过phpmyadmin访问MySQL,在一次数据库操作时想起没有设置密码,于是直接在mysql数据库中的us ...

  2. 从.NET的宠物商店到Android MVC MVP

    1 一些闲话 记得刚进公司的时候,我们除了做常规的Training Project外,每天还要上课,接受各种技术培训和公司业务介绍.当时第一次知道QA和SQA的区别.Training Project时 ...

  3. 多线程处理中Future的妙用

    java 中Future是一个未来对象,里面保存这线程处理结果,它像一个提货凭证,拿着它你可以随时去提取结果.在两种情况下,离开Future几乎很难办.一种情况是拆分订单,比如你的应用收到一个批量订单 ...

  4. swagger editor使用

    swagger editor使用 swagger是一套开源的API设计工具,包括Swagger UI,Swagger Editor等. Swagger Editor 其中Swagger Editor是 ...

  5. 浅析WPhone、Android的Back与Home键

    浅析WPhone.Android的Back与Home键 背景 本人一直在用诺基亚手机(目前是Nokia 925,Windows Phonre 8.1),在界面设计.应用多样性等方面没少受身边Andro ...

  6. Android视频播放之VideoView

    Android视频播放之VideoView 1.VideoView类介绍 Android的VideoView组件可以从不同的来源(例如资源文件或内容提供器)读取图像,计算和维护视频的画面尺寸以使其适用 ...

  7. ContentProvider数据访问详解

    ContentProvider数据访问详解 Android官方指出的数据存储方式总共有五种:Shared Preferences.网络存储.文件存储.外储存储.SQLite,这些存储方式一般都只是在一 ...

  8. [C#解惑] #2 对象的初始化顺序

    谜题 在上一篇C#解惑中,我们提到了对象的初始化顺序.当我们创建一个子类的实例时,总是会先执行基类的构造函数,然后再执行子类的构造函数.那么实例字段是什么时候初始化的呢?静态构造函数和静态字段呢?今天 ...

  9. SNMP 原理与实战详解

    原文地址:http://freeloda.blog.51cto.com/2033581/1306743 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法 ...

  10. Simple File System

    This is my operating system class design. scanner.h #include<string> using namespace std; #pra ...