164_超大区域个数问题(坐标离散化,压缩)

来源:互联网 发布:抗风计算软件 编辑:程序博客网 时间:2024/05/17 22:50

 区域个数问题,只不过行列都超大,无法在内存内搞数组来做。(下图来自《挑战程序竞赛》第二版 164页)



基本的做法就是进行矩阵压缩,使用坐标离散化的方法,对于行列的每个端点,加上做边的那个,再加上右边的那个,压入vector数组,排序,去除重复的元素,

然后用find方法找到端点的坐标,减去数组初始地址,便可求得压缩后的实际端点地址。

需要注意的又几点:

1. 程序中先排序,再使用了unique方法,unique 在数组中不是正真将重复的数据删去,只是讲重复的元素移到数组的末尾,比如:

{1,1,2,2,5,6,7} -> {1,2,5,6,7,1,2} 此时返回的是不重复的数组元素序列的最后一个元素的下一个元素地址(例子中为第二个1,类似于终止符的

作用);

2. 为了删除元素,要使用erase方法,讲上面所获得的元素地址到 数组末尾统统删除; 综合1,2 会有vector数组去重比较优雅的实现:

sort (xs.begin(),xs.end());xs.erase(unique( xs.begin(), xs.end() ), xs.end());

3. 书中给出的例子并不能体现优势,所以本人将矩阵扩大,体现优势,离散化压缩后优势体现明显;

4. 为保持程序的整洁性,并没有现则dfs(需要迭代),而选择bfs,保持了程序的完整性与可维护性;

5. bfs的时候转移的dx与dy书中没有给出,估计是漏写了,在下面的程序中本人补全了。


////  164_big lake counting.cpp//  changlle////  Created by user on 1/11/16.//  Copyright (c) 2016 user. All rights reserved.//#include <iostream>#include <queue>#include <vector>using namespace std;int W=100,H=100,N=5;int X1[5]={1,1,4,99,100};int X2[5]={6,100,4,99,100};int Y1[5]={4,8,1,1,6};int Y2[5]={4,8,100,5,100};//填充用bool fld[5*6][5*6];// 对x1与x2进行坐标离散化,并返回离散化之后的宽度int compress(int *x1, int *x2, int w) {    vector<int> xs;        for (int i=0;i<N;i++) {        for (int d=-1;d<=1;d++) {            int tx1=x1[i]+d,tx2=x2[i]+d;            if (1<=tx1 && tx1<=W) xs.push_back(tx1);            if (1<=tx2 && tx2<=W) xs.push_back(tx2);        }    }        sort (xs.begin(),xs.end());    xs.erase(unique( xs.begin(), xs.end() ), xs.end());        for (int i=0;i<N;i++) {        x1[i]=find(xs.begin(), xs.end(), x1[i])-xs.begin();        x2[i]=find(xs.begin(), xs.end(), x2[i])-xs.begin();    }        return xs.size();        }void solve() {        W=compress(X1,X2,W);    H=compress(Y1,Y2,H);    //cout<<W<<endl;    //cout<<H<<endl;        //开始填充    memset(fld,0,sizeof(fld));        for (int i=0;i<N;i++){        for (int y=Y1[i];y<=Y2[i];y++){            for (int x=X1[i];x<=X2[i];x++)                fld[y][x]=true;        }    }        for (int y=0;y<H;y++){        for (int x=0;x<W;x++) {            if (fld[y][x]) cout<<"*"<<" ";            else cout<<1<<" ";        }        cout<<endl;    }                        //求区域个数    int ans=0;        int dx[4]={-1,0,0,1};    int dy[4]={0,-1,1,0};        for (int y=0;y<H;y++){        for (int x=0;x<W;x++) {            if (fld[y][x]) continue;            ans++;                        //宽度优先搜索            queue<pair<int,int>> que;            que.push(make_pair(x,y));                        while (!que.empty()) {                                int sx=que.front().first, sy=que.front().second;                que.pop();                                                for (int i=0;i<4;i++) {                                        int tx=sx+dx[i],ty=sy+dy[i];                    if (tx<0 || W<=tx || ty<0 || H<=ty) continue;                    if (fld[ty][tx]) continue;                    que.push(make_pair(tx,ty));                    fld[ty][tx]=true;                }                            }        }    }        cout<<ans<<endl;}int main() {        solve();    return 0;}


0 0
原创粉丝点击