HDU 5925 Coconuts 离散化

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5925

Coconuts


Time Limit: 9000/4500 MS (Java/Others)Memory Limit: 65536/65536 K (Java/Others)
问题描述

TanBig, a friend of Mr. Frog, likes eating very much, so he always has dreams about eating. One day, TanBig dreams of a field of coconuts, and the field looks like a large chessboard which has R rows and C columns. In every cell of the field, there is one coconut. Unfortunately, some of the coconuts have gone bad. For sake of his health, TanBig will eat the coconuts following the rule that he can only eat good coconuts and can only eat a connected component of good coconuts one time(you can consider the bad coconuts as barriers, and the good coconuts are 4-connected, which means one coconut in cell (x, y) is connected to (x - 1, y), (x + 1, y), (x, y + 1), (x, y - 1).

Now TanBig wants to know how many times he needs to eat all the good coconuts in the field, and how many coconuts he would eat each time(the area of each 4-connected component).

输入

The first line contains apositiveinteger T(T≤10) which denotes the test cases. T test cases begin from the second line. In every test case, the first line contains two integers R and C, 0<R,C≤109 the second line contains an integer n, the number of bad coconuts, 0≤n≤200 from the third line, there comes n lines, each line contains two integers, xi and yi, which means in cell(xi,yi), there is a bad coconut.

It is guaranteed that in the input data, the first row and the last row will not have bad coconuts at the same time, the first column and the last column will not have bad coconuts at the same time.

输出

For each test case, output "Case #x:" in the first line, where x denotes the number of test case, one integer k in the second line, denoting the number of times TanBig needs, in the third line, k integers denoting the number of coconuts he would eat each time, you should output them in increasing order.

样例输入

2
3 3
2
1 2
2 1
3 3
1
2 2

样例输出

Case #1:
2
1 6
Case #2:
1
8

题意

给你一个n*m的网格,问障碍物把网格分割成多少个连通块,按从大到小的顺序输出每个连通块的大小。

题解

由于障碍就200多个,我们对障碍物离散化下,因为离散化不会影响被障碍物包围起来的连通块,所以离散化之后我们只统计被包围的那些(一个点事障碍物,要把它周围的点也离散化,否则会出现本来没被围起来的被围了),然后最后再算出外围的大块。
注意:在边缘的被分割开的连通块需要特殊处理下,这需要用到题目里面的一个提示:“the first row and the last row will not have bad coconuts at the same time, the first column and the last column will not have bad coconuts at the same time.”。我们标记下四周的状态,就可以判断我们统计的块是不是被夹在角落,还是离散化之后伪的被夹在角落。

代码

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf

typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;

const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0);

//start----------------------------------------------------------------------

const int maxn=222;

int R,C,n,nn,mm;

PII pt[maxn];
int vis[maxn][maxn];

const int dx[]= {-1,1,0,0};
const int dy[]= {0,0,-1,1};

bool _flag[4];
LL bfs(int xs,int ys) {
    queue<PII> Q;
    LL res=1;
    vis[xs][ys]=1;
    Q.push(mkp(xs,ys));
    int flag=0;
    while(!Q.empty()) {
        PII u=Q.front();
        Q.pop();
        int x=u.X,y=u.Y;
        for(int i=0; i<4; i++) {
            int nx=x+dx[i];
            int ny=y+dy[i];
            if(nx<1||nx>nn||ny<1||ny>mm) {
                if(nx<1&&_flag[0]==0) flag=1;
                if(nx>nn&&_flag[1]==0) flag=1;
                if(ny<1&&_flag[2]==0) flag=1;
                if(ny>mm&&_flag[3]==0) flag=1;
                continue;
            }
            if(!vis[nx][ny]) {
                vis[nx][ny]=1;
                res++;
                Q.push(mkp(nx,ny));
            }
        }
    }
    if(flag) return 0;
    return res;
}

int main() {
    int tc,kase=0;
    scf("%d",&tc);
    while(tc--) {
        scf("%d%d%d",&R,&C,&n);
        VI ha_x,ha_y;
        clr(_flag,0);
        rep(i,0,n) {
            scf("%d%d",&pt[i].X,&pt[i].Y);
            //标记四周的状态,用于判断被围在边缘的情况
            if(pt[i].X==1) _flag[0]=1;
            if(pt[i].X==R) _flag[1]=1;
            if(pt[i].Y==1) _flag[2]=1;
            if(pt[i].Y==C) _flag[3]=1;
            
                //离散化
            if(pt[i].X-1>=1) ha_x.pb(pt[i].X-1);
            ha_x.pb(pt[i].X);
            if(pt[i].X+1<=R) ha_x.pb(pt[i].X+1);

            if(pt[i].Y-1>=1) ha_y.pb(pt[i].Y-1);
            ha_y.pb(pt[i].Y);
            if(pt[i].Y+1<=C) ha_y.pb(pt[i].Y+1);
        }
        
            //离散化
        sort(all(ha_x));
        ha_x.erase(unique(all(ha_x)),ha_x.end());
        sort(all(ha_y));
        ha_y.erase(unique(all(ha_y)),ha_y.end());

        nn=ha_x.sz();
        mm=ha_y.sz();
        

            //外围的那个联通块
        LL Ma=(LL)R*C-n;
        vector<LL> ans;
        
            //离散化
        clr(vis,0);
        rep(i,0,n) {
            pt[i].X=lower_bound(all(ha_x),pt[i].X)-ha_x.begin()+1;
            pt[i].Y=lower_bound(all(ha_y),pt[i].Y)-ha_y.begin()+1;
            vis[pt[i].X][pt[i].Y]=1;
        }

        prf("Case #%d:\n",++kase);
        LL sum=0;
            //对于离散化的图暴力bfs
        for(int i=1; i<=nn; i++) {
            for(int j=1; j<=mm; j++) {
                if(!vis[i][j]) {
                    LL res=bfs(i,j);
                    if(res) {
                        sum+=res;
                        ans.pb(res);
                    }
                }
            }
        }
        Ma-=sum;
        if(Ma) ans.pb(Ma);

        sort(all(ans));

        prf("%d\n",ans.sz());
        rep(i,0,ans.sz()) {
            prf("%lld",ans[i]);
            if(i==ans.sz()-1) prf("\n");
            else prf(" ");
        }
    }

    return 0;
}

//end-----------------------------------------------------------------------

/*
222
4 4
4
1 2
2 1
2 3
3 2

7 7
4
3 4
4 3
4 5
5 4

*/

转载于:https://www.cnblogs.com/fenice/p/5942418.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值