【hdu4785】【闵可夫斯基和】 Exhausted Robot
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4785
题意:一个房间(矩形),里面有一些家具(凸多边形),你有一个扫地机器(凸多边形),扫地机器可以扫地是它的第一个点,能扫地条件是机器完全在房间里面并且和家具没有交(机器可以穿过家具,但穿过的时候不能扫地),问扫地机器扫到的最大面积。
题解:在房间内的限制等同于机器移动的限制是在一个矩形内,然后不交多边形的限制就变成了 家具 和 机器求一个闵可夫斯基和 , 机器移动不能移动到这个闵可夫斯基和里面,所以问题转换成一个矩形里面有若干个凸多边形,问矩形内多边形没有覆盖到的面积。
这里由于n只有20 , 我们可以考虑直接暴力扫描线。我们把多边形的顶点以及交点求出来,然后平行于y轴的扫面线一直扫过去,相邻的扫描线是一个区间片,多边形要么是不在区间片里面,要么是横穿了这个区间片,交的结果是一个梯形,注意到,多个多边形的交的梯形不会相交,因为假如相交了,那么交点肯定在区间片中间,那么区间片就应该缩小(因为是扫关键点),
由于刚刚的结论,所以我们直接用梯形面积公式求出区间片的面积,累加即可。
注意:对于一个多边形,我一个区间片统计其贡献的时候,当且仅当该多边形贯穿区间片,不然会出现问题,自己脑部一下就知道了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define eps 1e-8 4 const int N = 1e3+9; 5 const double inf = 1e6; 6 int sgn(double x){ 7 if( fabs(x) < eps) return 0; 8 if( x < 0 ) return -1; 9 return 1; 10 } 11 struct Point{ 12 double x,y; 13 Point operator - (const Point& b)const{ 14 return (Point){x-b.x,y-b.y}; 15 } 16 Point operator + (const Point& b)const{ 17 return (Point){x+b.x,y+b.y}; 18 } 19 bool operator < (const Point& b)const{ 20 if( sgn(x - b.x) == 0 ) return y < b.y; 21 return x < b.x; 22 } 23 }va[N],vb[N],rec[10]; 24 double cross(Point a,Point b){ 25 return a.x * b.y - b.x * a.y; 26 } 27 vector<Point> a[N],b[N]; 28 int n; 29 double xl,yl,xr,yr; 30 double X[N]; 31 double mi[N],mx[N]; 32 int cnt; 33 bool insert(Point a,Point b,Point c,Point d){ 34 return 35 max(a.x,b.x) >= min(c.x,d.x) && 36 max(c.x,d.x) >= min(a.x,b.x) && 37 max(a.y,b.y) >= min(c.y,d.y) && 38 max(c.y,d.y) >= min(a.y,b.y) && 39 sgn(cross(c-a,b-a))*sgn(cross(d-a,b-a))<=0 && 40 sgn(cross(a-c,d-c))*sgn(cross(b-c,d-c))<=0; 41 } 42 Point segcross(Point a,Point b,Point c,Point d){ 43 double u = cross(b-a,c-a) , v = cross(a-b,d-b); 44 return (Point){ (c.x*v+d.x*u)/(u+v) , (c.y*v+d.y*u)/(u+v)}; 45 } 46 vector<Point> Minke(vector<Point> pa,vector<Point> pb){ 47 int na = pa.size(),nb = pb.size(); 48 // 49 int ida = 0, idb = 0; 50 for(int i = 0;i<na;++i) if(pa[i] < pa[ida]) ida = i; 51 for(int i = 0;i<nb;++i) if(pb[i] < pb[idb]) idb = i; 52 vector<Point> ta , tb; 53 for(int i = 0;i<na;++i){ 54 ta.push_back(pa[ida]); 55 ida = (ida+1)%na; 56 } 57 for(int i = 0;i<nb;++i){ 58 tb.push_back(pb[idb]); 59 idb = (idb+1)%nb; 60 } 61 pa = ta; pb = tb; 62 63 for(int i = 0 ; i < na-1;++i) va[i] = pa[i+1] - pa[i]; 64 va[na-1] = pa[0] - pa[na-1]; 65 for(int i = 0 ; i < nb-1;++i) vb[i] = pb[i+1] - pb[i]; 66 vb[nb-1] = pb[0] - pb[nb-1]; 67 vector<Point> pc; 68 Point tem; 69 tem = pa[0] + pb[0]; 70 pc.push_back(tem); 71 int p1 = 0, p2 = 0; 72 while(p1 < na && p2 < nb){ 73 tem = tem + ( (cross(va[p1],vb[p2]) >= 0 ) ? va[p1++] : vb[p2++]); 74 pc.push_back(tem); 75 } 76 while(p1 < na){ 77 tem = tem + va[p1++]; 78 pc.push_back(tem); 79 } 80 while(p2 < nb){ 81 tem = tem + vb[p2++]; 82 pc.push_back(tem); 83 } 84 // 85 return pc; 86 } 87 void init(){ 88 double xmi = a[n+1][0].x,ymi = a[n+1][0].y,xmx = xmi , ymx = ymi; 89 for(auto it : a[n+1]){ 90 xmi = min(xmi,it.x) , xmx = max(xmx,it.x); 91 ymi = min(ymi,it.y) , ymx = max(ymx,it.y); 92 } 93 xl -= xmi; xr -= xmx; 94 yl -= ymi; yr -= ymx; 95 96 for(int i = 0;i<a[n+1].size();++i){ 97 a[n+1][i].x = -a[n+1][i].x; 98 a[n+1][i].y = -a[n+1][i].y; 99 } 100 for(int i = 1;i<=n;++i){ 101 b[i] = Minke(a[n+1],a[i]); 102 } 103 for(int i = 1;i<=n;++i){ 104 mi[i] = b[i][0].x , mx[i] = mi[i]; 105 for(auto it : b[i]){ 106 mi[i] = min(mi[i],it.x); 107 mx[i] = max(mx[i],it.x); 108 } 109 } 110 X[++cnt] = xl; 111 X[++cnt] = xr; 112 for(int i = 1;i<=n;++i){ 113 for(auto it : b[i]){ 114 if(it.x < xl + eps || it.x > xr - eps ) continue; 115 X[++cnt] = it.x; 116 } 117 } 118 for(int i = 1;i<=n;++i){ 119 for(int j = i+1;j<=n;++j){ 120 for(int ii = 0;ii<b[i].size()-1;++ii){ 121 for(int jj = 0;jj<b[j].size()-1;++jj){ 122 Point s1 = b[i][ii] , e1 = b[i][ii+1]; 123 Point s2 = b[j][jj] , e2 = b[j][jj+1]; 124 if( sgn(cross(e1 - s1,s2 - s1) ) == 0 && sgn(cross(e1 - s1,e2 - s1) == 0 ) ) continue; 125 if( insert(s1,e1,s2,e2) ){ 126 Point tem = segcross(s1,e1,s2,e2); 127 if(tem.x < xl + eps || tem.x > xr - eps ) continue; 128 X[++cnt] = tem.x; 129 } 130 } 131 } 132 } 133 } 134 rec[0] = (Point){xl,yl}; rec[1] = (Point){xr,yl}; 135 rec[2] = (Point){xr,yr}; rec[3] = (Point){xl,yr}; rec[4] = rec[0]; 136 for(int i = 1;i<=n;++i){ 137 for(int j = 0;j<b[i].size()-1;++j){ 138 for(int k = 0;k<4;++k){ 139 if(insert(b[i][j],b[i][j+1],rec[k],rec[k+1])){ 140 Point res = segcross(b[i][j],b[i][j+1],rec[k],rec[k+1]); 141 X[++cnt] = res.x; 142 } 143 } 144 } 145 } 146 sort(X+1,X+1+cnt); 147 } 148 void crosspol(vector<Point> p, double xx , vector< pair<double,int> >& Y){ 149 Point le = (Point){xx,-inf} , ri = (Point){xx,inf}; 150 vector<double> vec; 151 for(int j = 0;j<p.size()-1;++j){ 152 if( sgn( p[j].x - le.x) == 0 && sgn(p[j+1].x - le.x) == 0){ 153 vec.push_back(p[j].y); 154 vec.push_back(p[j+1].y); 155 } 156 else{ 157 if(insert(le,ri,p[j],p[j+1]) ){ 158 Point tem = segcross(le,ri,p[j],p[j+1]); 159 vec.push_back(tem.y); 160 } 161 } 162 } 163 sort(vec.begin(),vec.end()); 164 if(vec.size() < 2) return; 165 double ya = vec[0] , yb = vec[vec.size()-1]; 166 Y.push_back({max(ya,yl),1}); Y.push_back({min(yb,yr),-1}); 167 } 168 double solve_len(vector< pair<double,int> > Y){ 169 sort(Y.begin(),Y.end()); 170 int num = 0; 171 double res = 0; 172 double las; 173 for(auto it : Y){ 174 if(num==0 && it.second == 1){ 175 las = it.first; 176 ++num; 177 continue; 178 } 179 num += it.second; 180 if(num == 0 && it.second == -1) res += (it.first - las); 181 } 182 return res; 183 } 184 void solve(){ 185 double ans = 0; 186 for(int i = 1;i<cnt;++i){ 187 vector< pair<double,int> > Yl,Yr; 188 for(int j = 1;j<=n;++j){ 189 if(mx[j] < X[i] + eps || mi[j] > X[i+1] - eps ) continue; 190 crosspol(b[j],X[i],Yl); 191 crosspol(b[j],X[i+1],Yr); 192 } 193 double le = solve_len(Yl) , ri = solve_len(Yr); 194 ans += (ri + le) * (X[i+1] - X[i]) * 0.5; 195 } 196 printf("%.3f\n",(xr-xl)*(yr-yl) - ans); 197 return; 198 } 199 int main(){ 200 int T; scanf("%d",&T); 201 for(int cas = 1;cas <= T;++cas){ 202 cnt = 0; 203 printf("Case #%d: ",cas); 204 scanf("%d",&n); 205 for(int i = 1;i<=n+1;++i){ 206 a[i].clear(); 207 int m; scanf("%d",&m); 208 for(int j = 1;j<=m;++j){ 209 Point tem; 210 scanf("%lf %lf",&tem.x,&tem.y); 211 a[i].push_back(tem); 212 } 213 } 214 scanf("%lf %lf %lf %lf",&xl,&yl,&xr,&yr); 215 init(); 216 solve(); 217 } 218 return 0; 219 } 220 /* 221 6 222 1 223 3 224 0 0 225 10 0 226 10 10 227 4 228 0 0 229 1 0 230 1 1 231 0 1 232 0 0 10 10 233 */