Aizu 0531 "Paint Color" (坐标离散化+DFS or BFS 求联通子图个数)

传送门

题目描述:
    为了宣传信息竞赛,要在长方形的三合板上喷油漆来制作招牌。
    三合板上不需要涂色的部分预先贴好了护板。
    被护板隔开的区域要涂上不同的颜色,比如上图就应该涂上5种颜色。
    请编写一个程序计算涂色数量,输入数据中,保证看板不会被护板全部遮住,并且护板的边一定是水平或垂直的。

Input
    第一个数是宽w(1 ≤ w ≤ 1000000);
    第二个数是高h(1 ≤ h ≤ 1000000)。
    第二行是护板的数量n(1 ≤ n ≤ 1000);
    接着n行是每个护板的左下角坐标 (x1 , y1 )和右上角坐标 (x2 , y2 ),用空格隔开: x1 , y1 , x2 , y2 (0 ≤ x1< x2 ≤ w, 0 ≤ y1 < y2 ≤ h 都是整数)
    招牌的坐标系左下角是 (0, 0) ,右上角是(w, h)
Output
    颜色的数量
中文题目描述

中文题目描述摘抄自:https://blog.csdn.net/a1097304791/article/details/89707471

参考资料:

  [1]:挑战程序设计竞赛(第二版)

题解:

  坐标离散化+DFS求联通子图个数;

  注意:需要的是联通空格的个数,转化的时候需要注意 < 右边界,而不能等于;

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define mem(a,b) memset(a,b,sizeof(a))
  4 #define ll long long
  5 const int maxn=1e3+50;
  6 
  7 int n;
  8 int w,h;
  9 bool vis[6*maxn][6*maxn];
 10 struct Point
 11 {
 12     int x,y;
 13 }p[maxn],f,e;
 14 int dx[4]={0,0,-1,1};
 15 int dy[4]={1,-1,0,0};
 16 vector<int >vs[2];
 17 
 18 int BS(int l,int r,int x,int val)
 19 {
 20     int mid=l+((r-l)>>1);
 21     while(vs[x][mid] != val)
 22     {
 23         if(vs[x][mid] > val)
 24             r=mid;
 25         else
 26             l=mid;
 27         mid=l+((r-l)>>1);
 28     }
 29     return mid;
 30 }
 31 void Compress()
 32 {
 33     vs[0].clear();
 34     vs[1].clear();
 35     for(int i=1;i <= 2*(n+1);++i)
 36     {
 37         for(int d=-1;d <= 1;++d)
 38         {
 39             vs[0].push_back(p[i].x+d);///离散化x
 40             vs[1].push_back(p[i].y+d);///离散化y
 41         }
 42     }
 43     sort(vs[0].begin(),vs[0].end());
 44     sort(vs[1].begin(),vs[1].end());
 45     vs[0].erase(unique(vs[0].begin(),vs[0].end()),vs[0].end());
 46     vs[1].erase(unique(vs[1].begin(),vs[1].end()),vs[1].end());
 47 
 48     for(int i=1;i <= 2*(n+1);++i)
 49     {
 50         p[i].x=BS(0,vs[0].size(),0,p[i].x);///手动二分查找
 51         p[i].y=BS(0,vs[1].size(),1,p[i].y);
 52 //        p[i].x=find(vs[0].begin(),vs[0].end(),p[i].x)-vs[0].begin();
 53 //        p[i].y=find(vs[1].begin(),vs[1].end(),p[i].y)-vs[1].begin();
 54     }
 55     f=p[2*n+1];
 56     e=p[2*n+2];
 57 }
 58 bool isSat(int x,int y)
 59 {
 60     return x >= f.x && x < e.x && y >= f.y && y < e.y;
 61 }
 62 void DFS(int x,int y)
 63 {
 64     vis[x][y]=true;
 65     for(int i=0;i < 4;++i)
 66     {
 67         int nexX=x+dx[i];
 68         int nexY=y+dy[i];
 69         if(!isSat(nexX,nexY) || vis[nexX][nexY])
 70             continue;
 71         DFS(nexX,nexY);
 72     }
 73 }
 74 ll Solve()
 75 {
 76     Compress();
 77     mem(vis,false);
 78     for(int k=1;k <= n;++k)
 79     {
 80         for(int i=p[k].x;i < p[k+n].x;++i)///严格小于右边界
 81             for(int j=p[k].y;j < p[k+n].y;++j)///严格小于右边界
 82                 vis[i][j]=true;
 83     }
 84     ll ans=0;
 85     for(int i=f.x;i < e.x;++i)///严格小于右边界
 86         for(int j=f.y;j < e.y;++j)///严格小于右边界
 87             if(!vis[i][j])
 88             {
 89                 ans++;
 90                 DFS(i,j);
 91             }
 92     return ans;
 93 }
 94 int main()
 95 {
 96 //    freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin);
 97     while(~scanf("%d%d",&w,&h) && w+h)
 98     {
 99         scanf("%d",&n);
100         for(int i=1;i <= n;++i)
101         {
102             scanf("%d%d",&p[i].x,&p[i].y);
103             scanf("%d%d",&p[i+n].x,&p[i+n].y);
104         }
105         p[2*n+1]=Point{0,0};
106         p[2*n+2]=Point{w,h};
107 
108         printf("%lld\n",Solve());
109     }
110     return 0;
111 }
View Code

之所以做这道题,是因为省赛的时候,某题错解,用了离散化,按照书上写的find()函数,超时;

自己手写了个二分,返回了其他错误;

得出的结论是手写的二分 快于 find() 的时间复杂度;

tel me why?????

猜你喜欢

转载自www.cnblogs.com/violet-acmer/p/10872471.html