东北赛的一道二等奖题 当时学长想了一个dfs的解法并且通过了 那时自己也有一个bfs的解法没有拿出来 一直没有机会和时ji间xing来验证对错 昨天和队友谈离散化的时候想到了 于是用当时的思路做了一下
题意 : 一个 1e9 * 1e9 的棋盘,有 <=200 个格子是黑的,其他都是白的,问所有白色格子构成的四联通块有多大
因为棋盘规模过大 而黑点是少的 所以想到了离散化
一般离散化保证了离散之后 大小相等关系不变
把普遍的离散化做一下小修改 使相等的点离散化后相等 相邻的点离散化后相邻 有差距的点离散化后缩小差距到1
会发现 这样对黑点以及边界进行离散化之后 如果一个连通块被黑点包围 由于 相邻的点仍旧相邻 所以这个连通块离散化后 大小形状都不变
即 离散化之后 相邻点的骨架结构不变
那么肯定有空间被压缩了 这些被压缩的空间 就是 “有差距的点离散化后缩小差距到1” 这个时候缩小的空间
我称它为虚化空间 由题意 第一行列和最后一行列不同时有点 可以发现 如果虚化空间存在的话 最多只有一个 所有不存在于黑点包围范围的白点 都连接在一起 或许它们可能因为黑点的半包围结构没有缩小 但是它们一定会连接在一起 形成虚化空间
这个虚化空间的规模无法直接求出来(很多别的解法都并非用这种方法 而是压缩矩形) 但是我们知道 出去这个虚化空间 剩下的不是黑点就是被黑点包围的大小不变的白点
那么我们先对xy分别离散化 然后bfs掉虚化空间 剩下的连通块大小都是真实大小 那么虚化空间的size就是n*m-sum(其余联通块) - 黑点个数
bfs虚化空间或许是一个难点 因为并不知道哪个点连接进了这个虚化出来的连通块 但是由于第一行和最后一行不能同时有点这个设定 可以发现棋盘的四个角一定有一个点在虚化空间里面
例如 如果第一行和第一列没有点 那么就满足x最小的点和边界的差距大于1 统一缩小到1 则x为1的点可能存在于虚化空间 只要相对的y也被虚化了
所以 如果一个白点 它的xy不存在黑点拥有 就没有黑点为其支撑骨架 它就会被离散化
orz 终于 也算是给了当时的自己一个交代...
然 这个题有一个坑 它没有说给出的x y 的起点是0还是1
会发现唯一一个可能有说明意味的第一组样例 如果代入起点是0 是说得过去的 ...
但是代入起点是1 也是说得过去的...
de了一下午bug...摔
#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #include<map> #include<vector> #include<iostream> #include<iomanip> #include<algorithm> #include<queue> using namespace std; #define L long long L n , m ; L many ; L x[205]; L y[205]; struct node{ L pre; L now; }a[205]; bool cmp(node a, node b){ return a.pre < b.pre ; } L nn ; L mm ; bool cmp2(L a, L b){ return a < b ; } void lsh1(){ a[0].pre = -1; a[0].now = -1; nn = -1; for(L i = 1; i <= many ; i ++ ){ a[i].pre = x[i]; } a[many+1].pre = n ; sort(a+1,a+1+many+1,cmp) ; for(L i = 1; i <= many+1 ; i ++ ){ if(a[i].pre == a[i-1].pre){ a[i].now = a[i-1].now ; } else if(a[i].pre - a[i-1].pre == 1){ a[i].now = a[i-1].now + 1; } else { a[i].now = a[i-1].now + 2; } nn = max(nn , a[i].now) ; } for(L i = 1; i <= many; i ++ ){ for(L j = 1; j <= many ;j ++ ){ if(x[i] == a[j].pre){ x[i] = a[j].now ; break; } } } } void lsh2(){ a[0].pre = -1; a[0].now = -1; mm = -1; for(L i = 1; i <= many ; i ++ ){ a[i].pre = y[i]; } a[many+1].pre = m ; sort(a+1,a+1+many+1,cmp) ; for(L i = 1; i <= many+1; i ++ ){ if(a[i].pre == a[i-1].pre){ a[i].now = a[i-1].now ; } else if(a[i].pre - a[i-1].pre == 1){ a[i].now = a[i-1].now + 1; } else { a[i].now = a[i-1].now + 2; } mm = max(mm , a[i].now) ; } for(L i = 1; i <= many; i ++ ){ for(L j = 1; j <= many+1 ;j ++ ){ if(y[i] == a[j].pre){ y[i] = a[j].now ; break; } } } } bool vis[500][500] ; L ans[500] ; bool check(L x,L y){ if(x >= 0 &&x < nn && y >=0 && y < mm){ if(vis[x][y])return true; } return false ; } L dx[4] = {1,-1,0,0}; L dy[4] = {0,0,1,-1}; L bfs(L x,L y){ queue<L >que; que.push(x); que.push(y); vis[x][y]=false; L res = 1 ; while(!que.empty()){ L x = que.front();que.pop(); L y = que.front();que.pop(); for(L i = 0; i < 4; i ++ ){ L xx = dx[i] + x; L yy = dy[i] + y; if(check(xx,yy)){ que.push(xx); que.push(yy); vis[xx][yy]=false ; res ++ ; } } } return res ; } int main(){ L t ; scanf("%lld",&t); L cas = 1 ; while(t-- ){ scanf("%lld%lld",&n,&m) ; scanf("%lld",&many) ; bool qsx = false ; bool qsy = false ; for(L i = 1; i <= many ; i ++ ){ scanf("%lld%lld",&x[i],&y[i]) ; x[i] -- ; y[i] -- ; if(x[i] == 0)qsx = true ; if(y[i] == 0)qsy = true ; } memset(vis, true , sizeof(vis)) ; lsh1(); lsh2(); for(L i = 1; i <= many ; i ++ ){ vis[x[i]][y[i]] = false ; } L cnt = 0; L z ; if(qsx){ if(qsy){ z = bfs(nn-1,mm-1); } else z = bfs(nn-1,0) ; } else { if(qsy){ z = bfs(0,mm-1) ; } else z = bfs(0,0) ; } cnt ++ ; ans[cnt] = z; L sum = many ; for(L i = 0; i < nn ; i ++ ){ for(L j = 0; j < mm ; j ++ ){ if(vis[i][j]) { L dd = bfs(i,j) ; sum += dd; cnt ++ ; ans[cnt] = dd ; } } } ans[1] = n*m-sum; sort(ans+1,ans+1+cnt,cmp2); printf("Case #%lld: ",cas++); printf("%lld ",cnt); for(int i = 1; i <= cnt ;i ++ ){ printf("%lld",ans[i]); if(i==cnt)printf(" "); else printf(" "); } } }