Problem H. Tin Cutter II
In a Tin Cutting factory there isa machine for cutting parts from tin plates. It has an extraordinarily sharpknife able to make horizontal or vertical segment cuts in the tin plates. Eachcutting process consists of a sequence of such cuts. Each segment cut is givenby its endpoints that are always located inside the tin plate. During the cuttingprocess some parts of tin plate can fall out and so some holes in the plate canemerge.
Factory management needs topredict the length of visible border lines at the end of the given sequence ofcuts. Write a program that answers this question.
Here arefour examples:
The firstrow in the picture are four cuttings and the second row are their correspondingresulting plates. Each gray area is a separate hole, and thick lines arevisible border lines after cutting. There are 2, 2, 1, 1 holes respectively(from left to right), and the length of visible border lines are 8, 26, 12, 20respectively.
Input
The first line of input contains a single integer T (T<=100),the number of test cases. The first line of each test case contains aninteger n (1<=n<=100), the number ofsegment cuts. Each of the following n lines describe a segmentcut with four integers x1, y1, x2, y2 that means asegment cut from (x1,y1) to (x2,y2) (0<=x1,y1,x2,y2<=10000).The segment is always horizontal or vertical.
Output
For each test case, print the total lengthof the border lines.
Sample Input Output forSample Input
4 6 0 0 1 0 1 0 1 2 1 2 2 2 2 2 2 1 2 1 0 1 0 1 0 0 9 0 0 4 0 4 0 4 4 4 4 0 4 0 4 0 0 6 1 8 1 8 1 8 3 8 3 6 3 6 3 6 1 2 2 7 2 8 0 1 3 1 3 1 3 2 3 2 0 2 0 2 0 1 1 0 2 0 2 0 2 3 2 3 1 3 1 3 1 0 8 0 1 4 1 4 1 4 4 4 4 0 4 0 4 0 1 3 0 6 0 6 0 6 2 6 2 3 2 3 2 3 0 | 8 26 12 20 |
// Rujia Liu
#include<cstdio>
#include<cassert>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100*2 + 5;
const int maxv = 10000 + 5;
const int RIGHT = 0;
const int UP = 1;
int line[maxn][maxn][2]; // RIGHT and UP
int alive[maxn][maxn]; // alive[x][y] == 1 iff the square whose left-bottom corner is (x,y), is alive
int npx, npy; // number of points in x and y directions. points are numbered 1 to np*. squares are numbered 0 to np*
int xp[maxn], yp[maxn], idx[maxv], idy[maxv]; // xp[idx[v]] = v.
void dfs(int x, int y) {
if(alive[x][y]) return;
alive[x][y] = 1;
if(y < npy && !line[x][y+1][RIGHT]) dfs(x, y+1); // UP
if(y > 0 && !line[x][y ][RIGHT]) dfs(x, y-1); // DOWN
if(x > 0 && !line[x][y ][UP]) dfs(x-1, y); // LEFT
if(x < npx && !line[x+1][y][UP]) dfs(x+1, y); // RIGHT
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
int n, x1[maxn], y1[maxn], x2[maxn], y2[maxn], vis[maxv];
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%d%d%d%d", &x1[i], &y1[i], &x2[i], &y2[i]);
if(x1[i] == x2[i]) {
assert(y1[i] != y2[i]);
if(y1[i] > y2[i]) swap(y1[i], y2[i]);
} else {
assert(y1[i] == y2[i]);
if(x1[i] > x2[i]) swap(x1[i], x2[i]);
}
}
// discrete x
memset(vis, 0, sizeof(vis));
for(int i = 0; i < n; i++) vis[x1[i]] = vis[x2[i]] = 1;
npx = 0;
for(int i = 0; i < maxv; i++) if(vis[i]) {
xp[++npx] = i;
idx[i] = npx;
}
// discrete y
memset(vis, 0, sizeof(vis));
for(int i = 0; i < n; i++) vis[y1[i]] = vis[y2[i]] = 1;
npy = 0;
for(int i = 0; i < maxv; i++) if(vis[i]) {
yp[++npy] = i;
idy[i] = npy;
}
// draw lines in discrete grid
memset(line, 0, sizeof(line));
for(int i = 0; i < n; i++) {
if(x1[i] != x2[i]) for(int x = idx[x1[i]]; x < idx[x2[i]]; x++) line[x][idy[y1[i]]][RIGHT] = 1;
if(y1[i] != y2[i]) for(int y = idy[y1[i]]; y < idy[y2[i]]; y++) line[idx[x1[i]]][y][UP] = 1;
}
// floodfill
memset(alive, 0, sizeof(alive));
dfs(0, 0);
// accumulate answer
int ans = 0;
int lost = 0;
for(int x = 1; x <= npx; x++)
for(int y = 1; y <= npy; y++) {
if(!alive[x][y]) lost++;
if(line[x][y][RIGHT] && (alive[x][y] || alive[x][y-1])) ans += xp[x+1] - xp[x]; // check RIGHT
if(line[x][y][UP] && (alive[x][y] || alive[x-1][y])) ans += yp[y+1] - yp[y]; // check UP
}
printf("%d\n", ans);
}
return 0;
}