题目描述: 为了宣传信息竞赛,要在长方形的三合板上喷油漆来制作招牌。 三合板上不需要涂色的部分预先贴好了护板。 被护板隔开的区域要涂上不同的颜色,比如上图就应该涂上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 ",Solve()); 109 } 110 return 0; 111 }
之所以做这道题,是因为省赛的时候,某题错解,用了离散化,按照书上写的find()函数,超时;
自己手写了个二分,返回了其他错误;
得出的结论是手写的二分 快于 find() 的时间复杂度;
tel me why?????