Coconuts HDU - 5925 离散化+搜索求连通块面积与数量

Problem Description
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).

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.

Sample Input

2

3 3
2
1 2
2 1

3 3
1
2 2

Sample Output

Case #1:
2
1 6
Case #2:
1
8
问题可以简单描述为,告诉你图的大小(n*m <=1e9*1e9) 然后给你一些障碍物的坐标,问你四联联通块的个数有多少个 并输出每个连通块的大小。

傻逼题。。。。。。 障碍物的最多也只有两百个,而图的大小是1e9^2
明显是要离散化的。
离散化之后就是个求连通块的暴搜题型了。
但是!。。。。。 智障如我,组队训练的时候就是没想通怎么方便快速的求解连通块的大小。。。。
然后思路又被这句话给带歪了。。。。 居然想着求解每个被障碍物完全包围的连通块之后,再来处理其他的连通块的大小。。。。。
然后洋洋洒洒写了200行代码。。。。 调了一下午也没调过去。无FUCK说。

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.

我们其实可以先化简一下问题,假设没有离散化坐标,那么每个连通块的面积可以这么求

long long sum=0;
void dfs(int i,int j,int ln,int lm)
{
    if(i<0||j<0||i>=ln||j>=lm)
        return;
    if(maps[i][j]==-1)
        return;
    maps[i][j]=-1;
    sum++;
    for(int k=0;k<4;k++)
        dfs(i+diri[k],j+dirj[k],ln,lm);
}
for(int i=0;i<tni;i++)
        {
            for(int j=0;j<tnj;j++)
            {
                if(maps[i][j]!=-1)
                {
                    sum=0;
                    dfs(i,j,tni,tnj);
                    V.push_back(sum);
                }
            }
        }

这样子 每个空的点就只代表这一个点是完好的。

那么进一步的。 当我们离散化坐标之后, 每个点所代表的价值也会随之改变。
应该能很容易想到,每个点所代表的价值可以定义为

(ni[i]-(i>0?ni[i-1]:0))*(nj[j]-(j>0?nj[j-1]:0))

既这个点与距离他最近的左上方的那个“点”所围成的矩形面积。

这么一转换,这就是个裸地傻逼暴搜题了。
唯一要注意的是,如果坐标之间不连续的话,离散化的时候要在它们之间加上一个中间点
例如 18 20 应该离散为 hahs[0]=18 hahs[1]=19 hahs[2]=20;
太痛苦了,这么道傻逼题写了一下午。。。。。

#include <string>
#include<string.h>
#include<vector>
#include<queue>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<cstdio>
#include<iostream>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fuck(x) cout<<x<<endl
#define mem(a,b) memset(a,b,sizeof a)
int maps[1000][1000];
int hahsi[1000];
int hahsj[1000];
int ni[1000];
int nj[1000];
long long n,m;
class node
{
public:
    int i,j;
    node(int i=0,int j=0):i(i),j(j){}
};
node nodes[1000];
int diri[4]={0,0,-1,1};
int dirj[4]={1,-1,0,0};
long long sum=0;
void dfs(int i,int j,int ln,int lm)
{
    if(i<0||j<0||i>=ln||j>=lm)
        return;
    if(maps[i][j]==-1)
        return;
    maps[i][j]=-1;
    sum+=1ll * (ni[i]-(i>0?ni[i-1]:0))*(nj[j]-(j>0?nj[j-1]:0));
    for(int k=0;k<4;k++)
        dfs(i+diri[k],j+dirj[k],ln,lm);
}
int main()
{
    //freopen("input.txt","r",stdin);
    int T;
    scanf("%d",&T);
    int cases=0;
    while(T--)
    {
        memset(maps,0,sizeof maps);
        cin>>n>>m;
        //cout<<"fuck"<<n<<" "<<m<<endl;
        int c;
        scanf("%d",&c);
        int i,j;
        int toti=0,totj=0;
        for(int i1=0;i1<c;i1++)
        {
            scanf("%d %d",&i,&j);
            nodes[i1].i=i;
            nodes[i1].j=j;
            hahsi[toti++]=i;
            hahsj[totj++]=j;
        }
        hahsi[toti++]=n;hahsi[toti++]=1;
        hahsj[totj++]=m;hahsj[totj++]=1;
        sort(hahsi,hahsi+toti);
        sort(hahsj,hahsj+totj);
        toti=unique(hahsi,hahsi+toti)-hahsi;
        totj=unique(hahsj,hahsj+totj)-hahsj;
        ni[0]=hahsi[0];nj[0]=hahsj[0];
        int tni=1,tnj=1;
        for(int i=1;i<toti;i++)
        {
            if(hahsi[i]-ni[tni-1]>1)
            {
                ni[tni++]=hahsi[i]-1;
                ni[tni++]=hahsi[i];
            }
            else
            {
                ni[tni++]=hahsi[i];
            }
        }
        for(int j=1;j<totj;j++)
        {
            if(hahsj[j]-nj[tnj-1]>1)
            {
                nj[tnj++]=hahsj[j]-1;
                nj[tnj++]=hahsj[j];
            }
            else
            {
                nj[tnj++]=hahsj[j];
            }
        }
        for(int cnm=0;cnm<c;cnm++)
        {
            int nowi=lower_bound(ni,ni+tni,nodes[cnm].i)-ni;
            int nowj=lower_bound(nj,nj+tnj,nodes[cnm].j)-nj;
            maps[nowi][nowj]=-1;
        }
        vector<long long> V;
        for(int i=0;i<tni;i++)
        {
            for(int j=0;j<tnj;j++)
            {
                if(maps[i][j]!=-1)
                {
                    sum=0;
                    dfs(i,j,tni,tnj);
                    V.push_back(sum);
                }
            }
        }
        printf("Case #%d:\n",++cases);
        cout<<V.size()<<endl;
        sort(V.begin(),V.end());
        for(int i=0;i<V.size();i++)
        {
            if(i) cout<<" "<<V[i];
            else cout<<V[i];
        }
        cout<<endl;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值