HDU - 5925 D - Coconuts 二维数组的离散化问题

参考:https://www.cnblogs.com/stultus/p/6393444.html

他的行和列是反着的..wa了无数次...

学习使用了离散化这个知识点。

这道题最大的难点就是离散化之后如何计算每个区间内的小格子数量,因为常规的

离散化肯定会破坏小格子的数量的,所以我们需要记录一下啊。

如果对于x方向进行离散化时, 1  2  5  7位置分别存在一个坏椰子。

 那么我们离散化肯定离散成了 1 2 4 6有坏椰子。

这是我们需要知道被离散的那部分的真实长度。

1 2 3 4 5 6 7 8 9

。。. .  。.  。. .这是我们原本的

。。. 。. 。. .这是我们离散化后的。

1 1 2 1 1 1 2

对于每一列。


对于椰子列,我们肯定还是1,现在为1,离散后也为1.

对于空地,我们压缩成了1,但是这块空地实际长度为l【i】-l【i-1】-1的长度。记录一下。

所以我们dfs时,遍历到空地了,我们对于当前空地i,j。看起来就是1面积,实际的长度为x压缩之前的

长度*y压缩之前的长度。


#include <bits/stdc++.h>

using namespace std;
long long n,m;//n行m列
long long q;//q个坏椰子
struct node
{
    long long x;
    long long y;
};
long long sum;
long long mp[510][510];//压缩后的地图
vector<long long>hang_jiange;//记录x方向压缩,产生的间隔的实际长度。
vector<long long>lie_jiange;//记录y方向压缩,产生的间隔的实际长度。
int di[] = { 0,0,-1,1 };
int dj[] = { 1,-1,0,0 };
void dfs(int i, int j)
{
    if (mp[i][j] || i >= hang_jiange.size() || i < 0 || j >= lie_jiange.size() || j < 0)return;
    sum +=(long long ) hang_jiange[i] * (long long )lie_jiange[j];
    mp[i][j] = 1;
    for (int f = 0; f < 4; f++)
    {
        dfs(i + di[f], j + dj[f]);
    }
}
int main()
{
    int t;
    scanf("%d", &t);
    for(int tt=1;tt<=t;tt++)
    {
        map<long long,long long>mi,mj;
        cin>>m>>n;
        cin>>q;
        vector<long long>hang;
        vector<long long>lie;
        hang.push_back(0);
        hang.push_back(m);


        lie.push_back(0);
        lie.push_back(n);
        vector<node>yezi(q);
        for(int i=0;i<q;i++)
        {


            scanf("%lld%lld",&yezi[i].x,&yezi[i].y);
            hang.push_back(yezi[i].x);
            lie.push_back(yezi[i].y);
        }
        sort(hang.begin(),hang.end());
        sort(lie.begin(),lie.end());
        long long yasuohoudehang=unique(hang.begin(),hang.end())-hang.begin();
        long long yasuohuodelie=unique(lie.begin(),lie.end())-lie.begin();
        hang_jiange.clear();
        lie_jiange.clear();
        //我们hang_jiange记录的是每一个x坐标,被压缩之前的长度。坏椰子自身不会被压缩,就是1.实际所占面积就是1
        //而空地则会被压缩,压缩成1.实际是压缩了 左右椰子树之差-1”
        for(long long i=1;i<yasuohoudehang;i++)//处理行
        {


            if(hang[i]-hang[i-1]>1)//如果两个相邻x,差距大于1,我们依然是把它压缩成了1,但是他的实际长度为hang[i]-hang[i-1]-1
            {
                hang_jiange.push_back(hang[i]-hang[i-1]-1);//在默认的间隔之外,还会多出这些。这是被压缩的。
            }
            hang_jiange.push_back(1);//它自身是一个间隔,默认就是1


             mi[hang[i]]=hang_jiange.size()-1;//离散化
               //一一对应原则,对于hang[i]这个点,相对位置就是hang_jiange的大小


        }
         for(long long i=1;i<yasuohuodelie;i++)//处理行
        {


            if(lie[i]-lie[i-1]>1)
            {
                lie_jiange.push_back(lie[i]-lie[i-1]-1);
            }
             lie_jiange.push_back(1);


             mj[lie[i]]=lie_jiange.size()-1;


        }
        memset(mp,0,sizeof(mp));
        for(int i=0;i<q;i++)
        {
            long long xiangdui_x=mi[yezi[i].x];
            long long xiangdui_y=mj[yezi[i].y];
            mp[xiangdui_x][xiangdui_y]=1;
        }
        /离散化工作彻底完成,dfs开始


 /*for (int i = 0; i < hang_jiange.size(); i++)
        {
            for (int j = 0; j < lie_jiange.size(); j++)
            {
                if(mp[i][j])
                {
                    cout<<" ";
                }
                else cout<<"*";
            }


            cout<<endl;
        }
*/
        vector<long long>ans;//输出


          for (int i = 0; i < hang_jiange.size(); i++)
        {
            for (int j = 0; j < lie_jiange.size(); j++)
            {
                sum = 0;
                if (!mp[i][j])
                    dfs(i, j);
                if(sum)
                    ans.push_back(sum);
            }
        }


        sort(ans.begin(), ans.end());
         printf("Case #%d:\n", tt);
        cout << ans.size() << endl;
        for (int i = 0; i < ans.size(); i++)
        {
            if (i)
                printf(" %lld", ans[i]);
            else printf("%lld", ans[i]);
        }
        printf("\n");






    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值