読者です 読者をやめる 読者になる 読者になる

土下座しながら探索中

主に競技プログラミング

UVa 12509 : Tin Cutter II

問題リンク : http://uva.onlinejudge.org/external/125/12509.html

問題概要:
n本の線分が与えられる
線分はx軸かy軸に平行である
外側から到達可能な線分の部分の長さの総和を求めたい

解法 :
線分アレンジメント + 座標圧縮 + DFS
線分をアレンジメントして細分化する
細分化した線分の端点 + (それらの前後+-0.5) + 細分化した線分の中心点 を列挙し座標圧縮
どの点にも覆われていないような点からDFSを開始し、線分をまたがないで到達可能な場所を全て見る
それらのうち、線分の中心点に到達できたものを記録しておく
線分の中心に到達できた場合、その線分は最も外側であるのでそれらの線分の長さの総和をとる

コメント :
謎のREが多発した
compute内でメモリを取りすぎていたらしい
boolの2次元配列をすべてvector>にしたら回避できる

コード :

#include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define EPS (1e-6)
#define equals(a,b) (fabs((a)-(b)) < EPS)
#define COUNTER_CLOCKWISE 1
#define CLOCKWISE -1 
#define ONLINE_BACK 2
#define ONLINE_FRONT -2
#define ON_SEGMENT 0

using namespace std;

class Point{
public:
  double x,y;

  Point(double x = 0,double y = 0): x(x),y(y){}

  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  bool operator < (const Point& p) const{ return !equals(x,p.x)?x<p.x:(!equals(y,p.y)&&y<p.y); }
  bool operator == (const Point& p)const{ return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS; }

};

struct Segment{
  Point p1,p2;
  Segment(Point p1 = Point(),Point p2 = Point()):p1(p1),p2(p2){}
  bool operator <  (const Segment& s) const { return ( p2 == s.p2 ) ? p1 < s.p1 : p2 < s.p2; }
  bool operator == (const Segment& s) const { return ( s.p1 == p1 && s.p2 == p2 ) || ( s.p1 == p2 && s.p2 == p1 ); }

};

typedef Point Vector;
typedef Segment Line;

double dot(Point a,Point b){ return a.x*b.x + a.y*b.y; }
double cross(Point a,Point b){ return a.x*b.y - a.y*b.x; }
double norm(Point a){ return a.x*a.x+a.y*a.y; }
double abs(Point a){ return sqrt(norm(a)); }

int ccw(Point p0,Point p1,Point p2){
  Point a = p1-p0;
  Point b = p2-p0;
  if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
  if(cross(a,b) < -EPS)return CLOCKWISE;
  if(dot(a,b) < -EPS)return ONLINE_BACK;
  if(norm(a) < norm(b))return ONLINE_FRONT;
  return ON_SEGMENT;
}

double cross3p(Point p,Point q,Point r) { return (r.x-q.x) * (p.y -q.y) - (r.y - q.y) * (p.x - q.x); }
  
bool collinear(Point p,Point q,Point r) { return fabs(cross3p(p,q,r)) < EPS; }
 
bool onSegment(Point p,Point q,Point r){
  return collinear(p,q,r) && equals(sqrt(pow(p.x-r.x,2)+pow(p.y-r.y,2)) + sqrt(pow(r.x-q.x,2) + pow(r.y-q.y,2) ),sqrt(pow(p.x-q.x,2)+pow(p.y-q.y,2)) ) ;
}

bool intersectSS(Line s, Line t) {
  return ccw(s.p1,s.p2,t.p1)*ccw(s.p1,s.p2,t.p2) <= 0 &&
         ccw(t.p1,t.p2,s.p1)*ccw(t.p1,t.p2,s.p2) <= 0;
}

bool intersectSP(Line s, Point p) { return abs(s.p1-p)+abs(s.p2-p)-abs(s.p2-s.p1) < EPS; }

Point crosspoint(Line l,Line m){
  double A = cross(l.p2-l.p1,m.p2-m.p1);
  double B = cross(l.p2-l.p1,l.p2-m.p1);
  if(abs(A) < EPS && abs(B) < EPS){
    vector<Point> vec;
    vec.push_back(l.p1),vec.push_back(l.p2),vec.push_back(m.p1),vec.push_back(m.p2);
    sort(vec.begin(),vec.end());
    return vec[1];
  }
  return m.p1 + (m.p2-m.p1)*(B/A);
}

typedef pair<int,int> ii;
int dx[] = {0,1,0,-1};
int dy[] = {1,0,-1,0};
vector<Segment> segs;

bool  LT(double a,double b) { return !equals(a,b) && a < b; }
bool LTE(double a,double b) { return  equals(a,b) || a < b; } 

Point vir;
bool comp_dist(const Point &a,const Point &b){ return LT(abs(vir-a),abs(vir-b)); }
bool equal_d(const double &a,const double &b) { return equals(a,b); }

struct Double{
  double value;
  bool operator < ( const Double &d ) const { return LT(value,d.value); }
};

void compute(){
  vector<Segment> buf;
  rep(i,segs.size()) {
    vector<Point> vp;
    vp.push_back(segs[i].p1);
    vp.push_back(segs[i].p2);
    rep(j,segs.size()) if( i != j ) {
      if( equals(cross(segs[j].p1-segs[j].p2,segs[i].p1-segs[i].p2),0.0) ) {
        if( onSegment(segs[i].p1,segs[i].p2,segs[j].p1) ) vp.push_back(segs[j].p1);
        if( onSegment(segs[i].p1,segs[i].p2,segs[j].p2) ) vp.push_back(segs[j].p2);
      } else {
        if( intersectSS(segs[i],segs[j]) ) vp.push_back(crosspoint(segs[i],segs[j]));
      }
    }
    sort(vp.begin(),vp.end());
    vp.erase(unique(vp.begin(),vp.end()),vp.end());
    vir = segs[i].p1;
    sort(vp.begin(),vp.end(),comp_dist);
    rep(j,(int)vp.size()-1) buf.push_back(Segment(vp[j],vp[j+1]));
  }

  rep(i,(int)buf.size()) if( !( buf[i].p1 < buf[i].p2 ) ) swap(buf[i].p1,buf[i].p2);
  sort(buf.begin(),buf.end());
  buf.erase(unique(buf.begin(),buf.end()),buf.end());

  vector<double> X,Y;
  rep(i,(int)buf.size()){
    double xL = buf[i].p1.x, xR = buf[i].p2.x;
    double xM = ( xL + xR ) / 2.0;
    X.push_back(xM);
    for(double d=-0.5;LTE(d,0.5);d+=0.5) {
      double nx1 = xL + d, nx2 = xR + d;
      X.push_back(nx1); X.push_back(nx2);    
    }
    double yL = buf[i].p1.y, yR = buf[i].p2.y;
    double yM = ( yL + yR ) / 2;
    Y.push_back(yM);
    for(double d=-0.5;LTE(d,0.5);d+=0.5) {
      double ny1 = yL + d, ny2 = yR + d;
      Y.push_back(ny1); Y.push_back(ny2);
    }
  }
  
  sort(X.begin(),X.end(),LT);
  sort(Y.begin(),Y.end(),LT);
  X.erase(unique(X.begin(),X.end(),equal_d),X.end());
  Y.erase(unique(Y.begin(),Y.end(),equal_d),Y.end());
  map<Double,int> mp_x,mp_y;
  rep(i,(int)X.size()) mp_x[(Double){X[i]}] = i;
  rep(i,(int)Y.size()) mp_y[(Double){Y[i]}] = i;

  int W = mp_x.size(), H = mp_y.size();
  vector<vector<bool> > field(H+5,vector<bool>(W+5,false));
  rep(i,(int)buf.size()) {
    double y1 = buf[i].p1.y, y2 = buf[i].p2.y;
    if( LT(y2,y1) ) swap(y1,y2);
    for(int y=mp_y[(Double){y1}]+1;y<=mp_y[(Double){y2}]+1;y++) {
      double x1 = buf[i].p1.x, x2 = buf[i].p2.x;
      if( LT(x2,x1) ) swap(x1,x2);
      for(int x=mp_x[(Double){x1}]+1;x<=mp_x[(Double){x2}]+1;x++) {
        field[y][x] = true;
      }
    }
  }

  vector<int> MP[H+5][W+5];
  rep(i,(int)buf.size()){
    double x = ( buf[i].p1.x + buf[i].p2.x ) / 2.0, y = ( buf[i].p1.y + buf[i].p2.y ) / 2;
    int ix = mp_x[(Double){x}]+1, iy = mp_y[(Double){y}]+1;
    MP[iy][ix].push_back(i);
  }
  vector<int> reach;
  vector<vector<bool> > visited(H+5,vector<bool>(W+5,false));
  deque<ii> deq;
  deq.push_back(ii(0,0));
  visited[0][0] = true;
  while(!deq.empty()){
    ii cur = deq.front(); deq.pop_front();
    rep(i,4){
      int nx = cur.first + dx[i], ny = cur.second + dy[i];
      if( !( ( 0 <= nx && nx < W+5 ) && ( 0 <= ny && ny < H+5 ) ) ) continue;
      if( visited[ny][nx] ) continue;
      visited[ny][nx] = true;
      if( field[ny][nx] ) { 
        rep(j,(int)MP[ny][nx].size()) reach.push_back(MP[ny][nx][j]);
        continue; 
      }
      deq.push_back(ii(nx,ny));
    }
  }

  sort(reach.begin(),reach.end());
  reach.erase(unique(reach.begin(),reach.end()),reach.end());
  int answer = 0;
  rep(i,reach.size()) answer += (int)abs(buf[reach[i]].p1-buf[reach[i]].p2);
  cout << answer << endl;

}

int main(){
  int T;
  cin >> T;
  while( T-- ){
    int n;
    cin >> n;
    segs.resize(n);
    rep(i,n) cin >> segs[i].p1.x >> segs[i].p1.y >> segs[i].p2.x >> segs[i].p2.y;
    compute();
  }
  return 0;
}