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. Eclipse调试常用技巧(转)

    Eclipse调试常用技巧 转自http://daimojingdeyu.iteye.com/blog/633824 1. 条件断点 断点大家都比较熟悉,在Eclipse Java 编辑区的行头双击就 ...

  2. QTableView 一列添加两个按钮

    在QTableView的一列里添加两个按钮,之前添加一个按钮的思路是一样的,只是计算了一下按钮的宽,放两个按钮而已. 添加一个按钮的例子:QTableView 添加按钮 本例源代码:QtTowButt ...

  3. sencha xtype清单

    xtype Class ----------------- --------------------- actionsheet Ext.ActionSheet audio Ext.Audio butt ...

  4. P值与significant(显著性)的理解

    P值与significant的理解 来源:广州市统计局   发表日期:2015-01-21     P值可以理解为结论的风险大小,也就是根据数据得出的结果有多大的错误风险,P值越小,结论错误的风险越小 ...

  5. We Know What @You #Tag: Does the Dual Role Affect Hashtag Adoption-20160520

    分析类的论文 1.Information publication:www2012 author: Mei qiao zhu 2.What 微博中的hashtag既可以表示谈论的内容,又可以代表一个群体 ...

  6. go println与printf区别

    Println 与Printf 都是fmt 包中的公共方法 Println :可以打印出字符串,和变量: Printf : 只可以打印出格式化的字符串,可以输出字符串类型的变量,不可以输出整形变量和整 ...

  7. Collection中list集合的应用常见的方法

    集合 : 用存放对象的容器(集合)     Collection : 跟接口 : 单列集合          ---> List :有序的 ,元素是可以重复的.          ---> ...

  8. Linux IO Scheduler(Linux IO 调度器)

    每个块设备或者块设备的分区,都对应有自身的请求队列(request_queue),而每个请求队列都可以选择一个I/O调度器来协调所递交的request.I/O调度器的基本目的是将请求按照它们对应在块设 ...

  9. 链栈的C语言实现

    /* 功能:栈的链表实现 Author:lxm Date: 20160511 */ #include <stdio.h> #include <stdlib.h> #define ...

  10. 【UOJ #20】【NOIP 2014】解方程

    http://uoj.ac/problem/20 并不会做...然后看题解....... 对a取模,避免了高精度带来的复杂度,然后再枚举x判断是否满足模意义下等于0. 取5个模数,我直接抄的别人的_( ...