HDU 5925 Coconuts(离散化+bfs, 好题)

题目分析

求联通块但是R和C很大,用bfs很明显会超时,因此需要对其进行离散化,这一点我在我的前几篇博文中提过,但是本题还涉及到一个新的知识点,离散化之后还需要知道每个连通块中cell的个数,因此还需要一点小技巧,就是利用2个数组存储中间值。

#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 505;
#define LL long long
#define PII pair <int, int>
bool vis[maxn][maxn];
int R, C, n;
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
int x1[maxn], y1[maxn], x2[maxn], y2[maxn];
PII P[maxn];
map <int, int> X, Y;
LL ans[maxn];

void solve(){
    scanf("%d%d%d", &R, &C, &n);
    int num1 = 0; x1[++num1] = 1; x1[++num1] = R;  //注意边界值要加上,想一想为什么
    int num2 = 0; y1[++num2] = 1; y1[++num2] = C;
    for(int i = 0; i < n; i++){
        scanf("%d%d", &P[i].first, &P[i].second);
        x1[++num1] = P[i].first;
        y1[++num2] = P[i].second;
    }
    sort(x1+1, x1+num1+1);
    int xnum = unique(x1+1, x1+num1+1) - x1 - 1;
    sort(y1+1, y1+num2+1);
    int ynum = unique(y1+1, y1+num2+1) - y1 - 1;
    X.clear(), Y.clear();
    int xx = 0, yy = 0;
    for(int i = 1; i <= xnum; i++){
        if(x1[i] - x1[i-1] != 1)
            x2[++xx] = x1[i] - x1[i-1] - 1;
        x2[++xx] = 1;
        X[x1[i]] = xx;
    }
    for(int i = 1; i <= ynum; i++){
        if(y1[i] - y1[i-1] != 1)
            y2[++yy] = y1[i] - y1[i-1] - 1;
        y2[++yy] = 1;
        Y[y1[i]] = yy;
    }
    memset(vis, false, sizeof(vis));
    for(int i = 0; i < n; i++) vis[X[P[i].first]][Y[P[i].second]] = true;
//    printf("%d, %d\n", X[P[0].first], Y[P[0].second]);
    queue <PII> que;
    int flag = 0;
//    printf("xx = %d, yy = %d\n", xx, yy);
    for(int i = 1; i <= xx; i++){
        for(int j = 1; j <= yy; j++) if(!vis[i][j]) {
            LL cnt = 0;
            que.push(make_pair(i, j));
            vis[i][j] = true;
            while(!que.empty()){
                PII cur = que.front(); que.pop();
                cnt += (LL)x2[cur.first]*y2[cur.second];
 //               printf("x = %d, y = %d\n", x2[cur.first], y2[cur.second]);
                for(int k = 0; k < 4; k++){
                    int nx = cur.first + dir[k][0];
                    int ny = cur.second + dir[k][1];
                    if(nx < 1 || nx > xx || ny < 1 || ny > yy || vis[nx][ny]) continue;
                    vis[nx][ny] = 1;
                    que.push(make_pair(nx, ny));
                }
            }
            ans[flag++] = cnt;
        }
    }
    sort(ans, ans+flag);
    printf("%d\n", flag);
    for(int i = 0; i < flag; i++){
        if(i) printf(" ");
        printf("%I64d", ans[i]);
    }
    printf("\n");
}

int main(){
    int T;
    scanf("%d", &T);
    for(int kase = 1; kase <= T; kase++){
        printf("Case #%d:\n", kase);
        solve();
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值