土下座しながら探索中

主に競技プログラミング

AOJ 1288 : Digits on the Floor

問題リンク : Digits on the Floor | Aizu Online Judge

問題概要 :
線分の情報が与えられる
0から9の数字がそれぞれ何回現れるか数えよ
細かい制約は略

解法 :
最初にunion-findで繋がっている線分をまとめる
各まとまりについて、
各線分の別の線分と交差する回数を求め、昇順にvectorに詰める
このvectorが1,3,6,8の交差回数と同じであればそれがその数字となる
そうでない場合、
vectorが2,5と等しい時、
交差回数が1の線分と繋がっている線分との向きが時計回りであれば2
反時計ま回りであれば5
次に、
線分が別の線分の端点以外で交差するかどうかを確かめ、
交差するのであればそれは4または9
そうでないならば0または7

コード :

#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-8)
#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 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){}
};

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;
}

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;
}

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 ccwtest(Point p,Point q,Point r){ return cross3p(p,q,r) > 0; }
 
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)) ) ;
}

int par[1100];

int find(int x){
  if( x == par[x] ) return x;
  return par[x] = find(par[x]);
}

void unit(int x,int y){
  x = find(x), y = find(y);
  if( x != y ) par[x] = y;
}

vector<vector<int> > connect_counter;
int connect[10][6] = {
  {+2,+2,+2,+2,-1,-1},
  {+0,-1,-1,-1,-1,-1},
  {+1,+1,+2,+2,+2,-1},
  {+1,+1,+1,+3,-1,-1},
  {+1,+1,+2,-1,-1,-1},
  {+1,+1,+2,+2,+2,-1},
  {+1,+2,+2,+2,+3,-1},
  {+1,+1,+2,+3,-1,-1},
  {+2,+2,+2,+3,+3,-1},
  {+2,+2,+2,+2,-1,-1}
};

int WhatIsThis(vector<Segment> &segs){
  if( segs.size() == 1 ) return 1;
  vector<int> tmp;
  Segment cur,next;
  rep(i,segs.size()) {
    int cnt = 0;
    Segment touch;
    rep(j,segs.size()) if( i != j ) if( intersectSS(segs[i],segs[j]) ) {
        ++cnt;
        touch = segs[j];
      }
    if( cnt == 1 ) { cur = segs[i], next = touch; }
    assert( cnt );
    tmp.push_back(cnt);
  }
  sort(tmp.begin(),tmp.end());
  if( tmp == connect_counter[3] ) return 3;
  if( tmp == connect_counter[6] ) return 6;
  if( tmp == connect_counter[8] ) return 8;
  if( tmp == connect_counter[2] ) {
    Point p0,p1,p2;
    if( cur.p1 == next.p1 ) p0 = cur.p2, p1 = cur.p1, p2 = next.p2;
    if( cur.p1 == next.p2 ) p0 = cur.p2, p1 = cur.p1, p2 = next.p1;
    if( cur.p2 == next.p1 ) p0 = cur.p1, p1 = cur.p2, p2 = next.p2;
    if( cur.p2 == next.p2 ) p0 = cur.p1, p1 = cur.p2, p2 = next.p1;
    if( ccw(p0,p1,p2) == CLOCKWISE ) return 2;
    else                             return 5;
  }
  bool hasMiddle = false;
  rep(i,segs.size()) rep(j,segs.size()) if( i != j && intersectSS(segs[i],segs[j]) ) {
    if( segs[i].p1 == segs[j].p1 || segs[i].p1 == segs[j].p2 || segs[i].p2 == segs[j].p1 || segs[i].p2 == segs[j].p2 ) continue;
    hasMiddle = true;
    goto Skip;
  }
 Skip:;
  if( tmp == connect_counter[4] ) return (hasMiddle?4:7);
  if( tmp == connect_counter[0] ) return (hasMiddle?9:0);
  return -1;
}

void compute(int n,vector<Segment> &segs){
  vector<int> counter(10,0);
  
  rep(i,n) par[i] = i;
  rep(i,n) REP(j,i+1,n) if( intersectSS(segs[i],segs[j]) ) unit(i,j);
  int dex = 0;
  map<int,int> S;
  rep(i,n) if( !S.count(find(i)) ) S[find(i)] = dex++;
  int V = S.size();
  vector<vector<Segment> > buf(V,vector<Segment>());
  rep(i,n) buf[S[find(i)]].push_back(segs[i]);
  
  rep(i,V) {
    int result = WhatIsThis(buf[i]);
    ++counter[result];
  }

  rep(i,10) {
    if( i ) printf(" ");
    printf("%d",counter[i]);
  } puts("");
}

int main(){
  connect_counter.clear();
  connect_counter.resize(10,vector<int>());
  rep(i,10) rep(j,6) if( connect[i][j] != -1 ) connect_counter[i].push_back(connect[i][j]);
  int n;
  while( cin >> n, n ){
    vector<Segment> segs(n);
    rep(i,n) cin >> segs[i].p1.x >> segs[i].p1.y >> segs[i].p2.x >> segs[i].p2.y;
    compute(n,segs);
  }
  return 0;
}