矩形切割题目
hdu 3634 City Planning
题意:
给出n个矩形的左下角左边(x1,y1)以及右上角的坐标(x2,y2)以及每个矩形的单位面积所具有的的价值,求如何安排矩形的放置顺序是的总价值最大,输出总价值。
思路:
首先,这些矩形会有重叠的部分,重叠的部分肯定取val值最大的,所以我们首先按照每个矩形的val值排序,然后然后利用当前的矩形去切割前边切割出来的矩形,重叠部分肯定取当前的矩形的val计算,最后求切割出来的矩形的总价值即可。
View Code
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define ll __int64 #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout); #define M 30007 #define N 50007 using namespace std; const int inf = 100000007; const int mod = 1000000007; struct node { int p1[2],p2[2];//左下角的点,右上角的点 int val; }a[N],b[22]; int cmp(node a,node b) { return a.val < b.val; } //判断是否相交 bool intersect(node a,node b) { for (int i = 0; i < 2; ++i) { if (a.p2[i] <= b.p1[i] || a.p1[i] >= b.p2[i]) return false; } return true; } int tot; //用ta矩形切割tb矩形 void cut(node ta,node tb) { for (int i = 0; i < 2; ++i) { int k1 = max(ta.p1[i],tb.p1[i]); int k2 = min(ta.p2[i],tb.p2[i]); if (tb.p1[i] < k1) { a[++tot] = tb; a[tot].p2[i] = k1; } if (tb.p2[i] > k2) { a[++tot] = tb; a[tot].p1[i] = k2; } tb.p1[i] = k1; tb.p2[i] = k2; } } int main() { int T,i,j; int cas = 1; int n; scanf("%d",&T); while (T--) { scanf("%d",&n); for (i = 1; i <= n; ++i) { scanf("%d%d%d%d%d",&b[i].p1[0],&b[i].p1[1],&b[i].p2[0],&b[i].p2[1],&b[i].val); } sort(b + 1, b + 1 + n,cmp); tot = 0; for (i = 1; i <= n; ++i) { for (j = tot; j >= 1; --j) { if (intersect(b[i],a[j])) { cut(b[i],a[j]); a[j] = a[tot--];//覆盖掉原来切割后的矩形 } } //将最后的矩形放进来 a[++tot] = b[i]; } ll sum = 0; for (i = 1; i <= tot; ++i) { // printf("%d %d\n",i,a[i].val); sum += (ll)a[i].val*(a[i].p2[0] - a[i].p1[0])*(a[i].p2[1] - a[i].p1[1]); } printf("Case %d: %I64d\n",cas++,sum); } return 0; }
pku 2528 Mayor's posters
经典的贴海报的那个离散化+线段树的题目, 不过这里可以用矩形切割(这里是线段切割)来做,这里到了(10^8*T)不过可能后台数据比较弱,竟然也能过。
根据当前线段切割之前切出来的线段,然后求解即可。
View Code
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define ll __int64 #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout); #define M 30007 #define N 1000007 using namespace std; const int inf = 100000007; const int mod = 1000000007; struct node { int p1,p2; int col; }a,b[N]; bool vt[10007]; int tot; bool intersect(node a,node b) { if (a.p2 < b.p1 || a.p1 > b.p2) return false; return true; } void cut(node ta,node tb) { int k1 = max(ta.p1,tb.p1); int k2 = min(ta.p2,tb.p2); if (tb.p1 < k1) { b[++tot] = tb; b[tot].p2 = k1 - 1; } if (tb.p2 > k2) { b[++tot] = tb; b[tot].p1 = k2 + 1; } } int cmp(node a,node b) { return a.col < b.col; } int main() { int T,i,j; int n; scanf("%d",&T); while (T--) { scanf("%d",&n); tot = 0; for (i = 1; i <= n; ++i) { scanf("%d%d",&a.p1,&a.p2); a.col = i; for (j = tot; j >= 1; --j) { if (intersect(a,b[j])) { cut(a,b[j]); b[j] = b[tot--]; } } b[++tot] = a; } // sort(b + 1,b + 1 + tot,cmp); int ans = 0; CL(vt,false); for (i = 1; i <= tot; ++i) { if (!vt[b[i].col]) { ans++; vt[b[i].col] = true; } } printf("%d\n",ans); } return 0; }
pku 1151 Atlantis
同样是经典的线段树求矩形面积并的题目,这里用矩形切割的话,代码量很短。
同时注意精度的处理,同时还要理解一个问题,当我们给出左上角和右下角的坐标是我们是按照左上角为(0,0)建立的坐标系,如果给出左下角和右上角的时候是按照左下角为(0,0)建立的图,所以我们的for循环处理判断相交是都是对的。
View Code
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define ll __int64 #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout); #define M 30007 #define N 107 using namespace std; const int inf = 100000007; const int mod = 1000000007; const double eps = 1e-6; struct node { double p1[2],p2[2]; }a,b[N*N]; int tot; int dblcmp(double x) { if (x > eps) return 1; else if (x < -eps) return -1; else return 0; } bool intersect(node ta,node tb) { for (int i = 0; i < 2; ++i) { if (dblcmp(ta.p2[i] - tb.p1[i]) <= 0 || dblcmp(ta.p1[i] - tb.p2[i]) >= 0) return false; } return true; } void cut(node ta,node tb) { for (int i = 0; i < 2; ++i) { int k1 = max(ta.p1[i],tb.p1[i]); int k2 = min(ta.p2[i],tb.p2[i]); if (dblcmp(tb.p1[i] - k1) < 0) { b[++tot] = tb; b[tot].p2[i] = k1; } if (dblcmp(tb.p2[i] - k2) > 0) { b[++tot] = tb; b[tot].p1[i] = k2; } tb.p1[i] = k1; tb.p2[i] = k2; } } int main() { int n,i,j; int cas = 1; while (~scanf("%d",&n)) { if (!n) break; tot = 0; for (i = 1; i <= n; ++i) { scanf("%lf%lf%lf%lf",&a.p1[0],&a.p1[1],&a.p2[0],&a.p2[1]); for (j = tot; j >= 1; --j) { if (intersect(a,b[j])) { cut(a,b[j]); b[j] = b[tot--]; } } b[++tot] = a; } double sum = 0; for (i = 1; i <= tot; ++i) { sum += (b[i].p2[0] - b[i].p1[0])*(b[i].p2[1] - b[i].p1[1]); } printf("Test case #%d\n",cas++); printf("Total explored area: %.2lf\n\n",sum); } return 0; }
pku 3277 City Horizon
题意:
给出n个矩形的最下边一条边在x轴上的坐标以及该矩形的高度,求n个矩形面积的并。
思路:
n很大,觉得矩形切割肯定会超时,怎么会分到矩形切割呢。于是就将给出的矩形转化成左下角坐标和右上角坐标,求解。结果真的tle了。后来看了看解题报告, 原来按照高度排序转化成线段切割就好了。不过感觉数据量依然很大,理论上应该是会超时的可是这里可能是后台数据弱吧。
View Code
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define ll long long #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout); #define M 30007 #define N 4000007 using namespace std; const int inf = 100000007; const int mod = 1000000007; const double eps = 1e-6; struct node { ll p1,p2; ll h; }a[N],b[N]; int tot; int cmp(node a,node b) { return a.h < b.h; } bool intersect(node ta,node tb) { if (ta.p2 <= tb.p1 || ta.p1 >= tb.p2) return false; return true; } void cut(node ta,node tb) { ll k1 = max(ta.p1,tb.p1); ll k2 = min(ta.p2,tb.p2); if (tb.p1 < k1) { b[++tot] = tb; b[tot].p2 = k1; } if (tb.p2 > k2) { b[++tot] = tb; b[tot].p1 = k2; } } int main() { // Read(); int i,j,n; scanf("%d",&n); for (i = 1; i <= n; ++i) { scanf("%I64d%I64d%I64d",&a[i].p1,&a[i].p2,&a[i].h); } sort(a + 1,a + 1 + n,cmp); tot = 0; for (i = 1; i <= n; ++i) { for (j = tot; j >= 1; --j) { if (intersect(a[i],b[j])) { cut(a[i],b[j]); b[j] = b[tot--]; } } b[++tot] = a[i]; } ll sum = 0; for (i = 1; i <= tot; ++i) { sum += (b[i].p2 - b[i].p1)*b[i].h; } cout<<sum<<endl; return 0; }