Problem p01318 (C++) — buggy submission, verdict: Runtime Error

#include <algorithm>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>
using namespace std;
#define rep(i, n) for (int i = 0; i < ((int)(n)); i++)
#define reg(i, a, b) for (int i = ((int)(a)); i <= ((int)(b)); i++)
#define irep(i, n) for (int i = ((int)(n)) - 1; i >= 0; i--)
#define ireg(i, a, b) for (int i = ((int)(b)); i >= ((int)(a)); i--)
typedef long long int lli;
typedef pair<int, int> mp;
#define fir first
#define sec second
#define IINF INT_MAX
#define LINF LLONG_MAX
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#define pque(type) priority_queue<type, vector<type>, greater<type>>
#define memst(a, b) memset(a, b, sizeof(a))
#define iter(v, ite) for (auto ite = (v).begin(); ite != (v).end(); ite++)
#define mimunum(v, x)                                                          \\
  distance((v).begin(), lower_bound((v).begin(), (v).end(), x))

struct makehtml {
  vector<string> ss;

  makehtml() {}
  /*
  ctx.beginPath()
  ctx.moveTo(50.000000,100.000000);
  ctx.lineTo(150.000000,100.000000);
  ctx.stroke();

  ctx.fillStyle = "rgb(0,0,0)";

  ctx.beginPath();
  ctx.arc(168,59,3,0,360);
  ctx.fill();

  */

  void out(const char *name, double mag) {
    char fname[100];
    sprintf(fname, "%s.html", name);
    FILE *fp = fopen(fname, "w");
    if (fp == NULL) {
      eprintf("can't open %s\\b", fname);
      exit(-1);
    }
    fprintf(fp, "<html>\\n<head>\\n<title>");
    fprintf(fp, "%s", name);
    fprintf(fp, "</title>\\n</head>\\n<body>\\n");
    fprintf(fp, "<p>name: %s</p>", name);
    fprintf(fp, "<canvas id=\\"vis\\" width=\\"%d\\" height=\\"%d\\"></canvas>", 2000,
            2000);
    fprintf(fp, "<script>\\n");
    fprintf(fp, "var vis = document.getElementById('vis');\\nvar ctx = "
                "vis.getContext('2d');\\n");

    rep(i, ss.size()) { fprintf(fp, "%s\\n", ss[i].c_str()); }

    fprintf(fp, "</script>\\n");
    fprintf(fp, "</body>\\n</html>\\n");
    fclose(fp);
  }

} makehtml_instance;

void addhtml(string s) { makehtml_instance.ss.push_back(s); }

void outhtml(string s, double mag) { makehtml_instance.out(s.c_str(), mag); }

void randcolhtml() {
  char ns[100];
  sprintf(ns, "ctx.fillStyle = \\"rgb(%d,%d,%d)\\";", rand() % 128, rand() % 128,
          rand() % 128);
  addhtml(ns);
  sprintf(ns, "ctx.strokeStyle = \\"rgb(%d,%d,%d)\\";", rand() % 128,
          rand() % 128, rand() % 128);
  addhtml(ns);
}

void inithtml() { makehtml_instance.ss.clear(); }

const double pi = 3.14159265358979;

struct pos {
  double x, y;
  double norm, norm2;
  pos tov(pos a) { return (a - (*this)); }
  pos operator+(pos a) const {
    pos res = a;
    res.x += x;
    res.y += y;
    res = pos(res.x, res.y);
    return res;
  }
  pos operator-(pos a) const {
    pos res = (*this);
    res.x -= a.x;
    res.y -= a.y;
    res = pos(res.x, res.y);
    return res;
  }
  pos scalar(double a) {
    pos res = (*this);
    res.x *= a;
    res.y *= a;
    res = pos(res.x, res.y);
    return res;
  }
  double dot(pos a) { return x * a.x + y * a.y; }
  double cross(pos a) { return x * a.y - y * a.x; }
  double theta(pos a) {
    double nt = dot(a) / (norm * a.norm);
    nt = acos(max(-1.0, min(1.0, nt)));
    double ns = (cross(a) / (norm * a.norm));
    if (ns < 0)
      nt *= -1;
    return nt;
  }
  pos(double ix, double iy) {
    x = ix;
    y = iy;
    norm2 = x * x + y * y;
    norm = sqrt(norm2);
  }
  pos() {}
  string str() {
    char ns[50];
    sprintf(ns, "(%lf %lf)", x, y);
    return string(ns);
  }
  void outh(double mag) {
    char ns[50];
    addhtml("ctx.beginPath();");
    sprintf(ns, "ctx.arc(%lf,%lf,%lf,0,360);", x * mag, y * mag, 5.0);
    addhtml(ns);
    addhtml("ctx.fill();");
  }
  static pos polar(double r, double t) { return pos(r * cos(t), r * sin(t)); }
  pos turn(double t) {
    // t[rad]??????
    return pos(x * cos(t) - y * sin(t), x * sin(t) + y * cos(t));
  }
  pos tolen(double a) {
    //?????????a?????????
    return this->scalar(a / norm);
  }
  bool operator<(pos a) const {
    // if(x!=a.x)return (x<a.x);
    // return (y<a.y);
    if (y != a.y)
      return (y < a.y);
    return (x < a.x);
  }
  bool operator>(pos a) const { return (a < (*this)); }
};
struct line {
  pos p, q;
  pos vec;
  string str() { return ("(" + p.str() + "-" + q.str() + ")"); }
  void outh(double mag) {
    char ns[50];
    addhtml("ctx.beginPath();");
    sprintf(ns, "ctx.moveTo(%lf,%lf);", p.x * mag, p.y * mag);
    addhtml(ns);
    sprintf(ns, "ctx.lineTo(%lf,%lf);", q.x * mag, q.y * mag);
    addhtml(ns);
    addhtml("ctx.stroke();");
  }
  bool iscross(line a) {
    double da, db;
    da = vec.cross(p.tov(a.p));
    db = vec.cross(p.tov(a.q));
    if (da * db >= 0)
      return false;
    da = a.vec.cross(a.p.tov(p));
    db = a.vec.cross(a.p.tov(q));
    return (da * db < 0);
  }
  line(pos ip, pos iq) {
    p = ip;
    q = iq;
    vec = p.tov(q);
  }
  line() {}
  double dist(pos a) {
    if (p.tov(a).dot(p.tov(q)) < 0)
      return p.tov(a).norm;
    if (q.tov(a).dot(q.tov(p)) < 0)
      return q.tov(a).norm;
    return abs(vec.cross(p.tov(a)) / vec.norm);
  }
  double dist(line a) {
    if (iscross(a))
      return 0;
    return min(min(dist(a.p), dist(a.q)),
               min(a.dist(this->p), a.dist(this->q)));
  }
  pos crosspos(line a) {
    /*
    double d1=a.vec.cross(a.p.tov(p))/a.vec.norm;
    double d2=a.vec.cross(a.p.tov(q))/a.vec.norm;
    bool isc=(d1*d2<0);
    d1=abs(d1); d2=abs(d2);
    double sc;
    if(!isc){
            if(d1>d2)sc = d1/(d1-d2);
            else sc=d1/(d2-d1);
    }
    else sc = d1/(d1+d2);
    return (p+vec.scalar(sc));*/

    double t = a.vec.cross(a.p - p) / a.vec.cross(vec);
    return (p + vec.scalar(t));
  }
  line bisection() { //?????´????????????
    //???????¨??????????90????????£???????????????
    pos fr = (p + q).scalar(0.5);
    pos to = fr + pos(-vec.y, vec.x);
    return line(fr, to);
  }
};
double lowofcos_getcos(double a, double b, double c) {
  return ((a * a + b * b - c * c) / (2 * a * b));
}
struct circle {
  pos p;
  double r;
  line koten(circle a) {
    pos cv = p.tov(a.p);
    double br = atan2(cv.y, cv.x);
    double dr = acos(lowofcos_getcos(r, cv.norm, a.r));
    pos p1 = p + pos::polar(r, br + dr);
    pos p2 = p + pos::polar(r, br - dr);
    if (p1 > p2)
      swap(p1, p2);
    return line(p1, p2);
  }
  circle(pos ip, double ir) {
    p = ip;
    r = ir;
  }
  circle() {}
  void outh(double mag) {
    char ns[50];
    addhtml("ctx.beginPath();");
    sprintf(ns, "ctx.arc(%lf,%lf,%lf,0,360);", p.x * mag, p.y * mag, r * mag);
    addhtml(ns);
    addhtml("ctx.stroke();");
  }

  vector<line> tangs(circle a) { //??\\?????????
    circle b(*this);
    if (a.r < b.r)
      swap(a, b);
    vector<line> res;
    if ((a.p - b.p).norm - (a.r - b.r) < 0.0)
      return res;
    if ((a.p - b.p).norm - (a.r - b.r) < 1e-6) {
      if ((b.p - a.p).norm < 1e-6)
        return res; //??¨???????????????
      pos rv = (b.p - a.p).tolen(a.r);
      res.push_back(line(rv + a.p, rv + a.p + rv.turn(pi / 2.0)));
      return res;
    }
    {
      pos cv = b.p - a.p;
      double th = acos((a.r - b.r) / cv.norm);
      pos p1 = cv.turn(th);
      res.push_back(line(a.p + p1.tolen(a.r), b.p + p1.tolen(b.r)));
      pos p2 = cv.turn(-th);
      res.push_back(line(a.p + p2.tolen(a.r), b.p + p2.tolen(b.r)));
    }
    if ((a.p - b.p).norm - (a.r + b.r) < 0.0)
      return res;
    if ((a.p - b.p).norm - (a.r + b.r) < 1e-6) {
      pos rv = (b.p - a.p).tolen(a.r);
      res.push_back(line(rv + a.p, rv + a.p + rv.turn(pi / 2.0)));
      return res;
    }
    {
      pos cv = b.p - a.p;
      double th = acos((a.r + b.r) / cv.norm);
      pos p1 = cv.turn(th);
      res.push_back(line(a.p + p1.tolen(a.r), b.p + p1.tolen(-b.r)));
      pos p2 = cv.turn(-th);
      res.push_back(line(a.p + p2.tolen(a.r), b.p + p2.tolen(-b.r)));
    }
    return res;
  }
};

struct polygon {
  vector<pos> ps;
  polygon() {}
  void outh(double mag) {
    char ns[50];
    addhtml("ctx.beginPath();");
    int ls = ps.size();
    sprintf(ns, "ctx.moveTo(%lf,%lf);", ps[ls - 1].x * mag, ps[ls - 1].y * mag);
    addhtml(ns);
    rep(i, ps.size()) {
      sprintf(ns, "ctx.lineTo(%lf,%lf);", ps[i].x * mag, ps[i].y * mag);
      addhtml(ns);
    }
    addhtml("ctx.stroke();");
  }
  double area() {
    double res = 0;
    rep(i, ps.size()) {
      pos no = ps[i], to = ps[(i + 1) % ps.size()];
      res += (no.x + to.x) * (no.y - to.y);
    }
    if (res < 0)
      reverse(ps.begin(), ps.end());
    return abs(res) / 2;
  }
  polygon(pos a, pos b) {
    ps.push_back(a);
    ps.push_back(pos(a.x, b.y));
    ps.push_back(b);
    ps.push_back(pos(b.x, a.y));
  }
  line gete(int a) {
    a %= ps.size();
    return line(ps[a], ps[(a + 1) % ps.size()]);
  }
  int isin(pos a) { //?????´??????2,?????£????????????1,?????????0
    double as = 0;
    rep(i, ps.size()) {
      line ne = gete(i);
      if (ne.dist(a) <= 0)
        return 1;
      pos v1 = a.tov(ne.p);
      pos v2 = a.tov(ne.q);
      as += v1.theta(v2);
    }
    if (abs(as) < 1e-6)
      return 0;
    return 2;
  }
  polygon convex_full() {
    polygon res;
    int ns = ps.size();
    vector<pos> vs(2 * ns);
    sort(ps.begin(), ps.end());
    int k = 0;
    rep(i, ns) {
      pos np = ps[i];
      while (k > 1 && vs[k - 2].tov(vs[k - 1]).cross(vs[k - 1].tov(np)) < -1e-6)
        k--;
      vs[k] = np;
      k++;
    }
    int t = k;
    ireg(i, 0, ns - 2) {
      pos np = ps[i];
      while (k > t && vs[k - 2].tov(vs[k - 1]).cross(vs[k - 1].tov(np)) < -1e-6)
        k--;
      vs[k] = np;
      k++;
    }
    vs.resize(k - 1);
    swap(vs, res.ps);
    return res;
  }
  polygon cut(line a) { //???????????????????????????
    polygon res;
    rep(i, ps.size()) {
      line ne = gete(i);
      double d1 = a.vec.cross(a.p.tov(ne.p));
      double d2 = a.vec.cross(a.p.tov(ne.q));
      if (d1 < 1e-6)
        res.ps.push_back(ne.p); //?????£????????£???eps
      if (d1 * d2 < -1e-6)
        res.ps.push_back(a.crosspos(ne)); //?????£????????????eps
    }
    return res;
  }

  vector<polygon> voronoi(vector<pos> ps) {
    // validate AOJ 2160
    vector<polygon> res;
    rep(i, ps.size()) {
      polygon np(*this);
      rep(j, ps.size()) {
        if (i == j)
          continue;
        line nl = line(ps[j], ps[i]).bisection();

        np = np.cut(nl);
      }
      res.push_back(np);
    }
    return res;
  }
  polygon mult(polygon a) { return a; }
};

int main(void) {
  for (;;) {
    int n;
    scanf("%d", &n);
    if (n == 0)
      break;
    vector<circle> cs;
    rep(i, n) {
      double x, y, r, m;
      scanf("%lf%lf%lf%lf", &x, &y, &r, &m);
      x += 10;
      y += 10;
      cs.push_back(circle(pos(x, y), r));
      cs.push_back(circle(pos(x, y), r + m));
    }
    if (n == 1) {
      printf("1\\n");
      continue;
    }

    int ans = 0;
    rep(i, 2 * n) {
      rep(j, i) {
        if (i % 2 == 1 && i - 1 == j)
          continue;
        vector<line> ls = cs[i].tangs(cs[j]);
        rep(k, ls.size()) {
          // inithtml();
          line e = ls[k];
          e = line(e.p + e.vec.tolen(-3000), e.p + e.vec.tolen(3000));
          // e.outh(10);

          int na = 0;
          rep(p, n) {
            // cs[p*2].outh(10);
            // cs[p*2+1].outh(10);

            double d = e.dist(cs[p * 2].p);
            if (d + 1e-6 < cs[p * 2].r)
              continue;
            if (cs[p * 2 + 1].r + 1e-6 < d)
              continue;
            na++;
          }
          ans = max(ans, na);
          // printf("na %d %d %d %s %d\\n",i,j,k,e.str().c_str(),na);
          /*
          char buf[20];
          sprintf(buf,"o_%d_%d_%d",i,j,k);
          outhtml(buf,10);
          */
        }
      }
    }
    printf("%d\\n", ans);
  }
  return 0;
}

Error: 0

Fixed submission:

#include <algorithm>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>
using namespace std;
#define rep(i, n) for (int i = 0; i < ((int)(n)); i++)
#define reg(i, a, b) for (int i = ((int)(a)); i <= ((int)(b)); i++)
#define irep(i, n) for (int i = ((int)(n)) - 1; i >= 0; i--)
#define ireg(i, a, b) for (int i = ((int)(b)); i >= ((int)(a)); i--)
typedef long long int lli;
typedef pair<int, int> mp;
#define fir first
#define sec second
#define IINF INT_MAX
#define LINF LLONG_MAX
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#define pque(type) priority_queue<type, vector<type>, greater<type>>
#define memst(a, b) memset(a, b, sizeof(a))
#define iter(v, ite) for (auto ite = (v).begin(); ite != (v).end(); ite++)
#define mimunum(v, x)                                                          \\
  distance((v).begin(), lower_bound((v).begin(), (v).end(), x))

struct makehtml {
  vector<string> ss;

  makehtml() {}
  /*
  ctx.beginPath()
  ctx.moveTo(50.000000,100.000000);
  ctx.lineTo(150.000000,100.000000);
  ctx.stroke();

  ctx.fillStyle = "rgb(0,0,0)";

  ctx.beginPath();
  ctx.arc(168,59,3,0,360);
  ctx.fill();

  */

  void out(const char *name, double mag) {
    char fname[100];
    sprintf(fname, "%s.html", name);
    FILE *fp = fopen(fname, "w");
    if (fp == NULL) {
      eprintf("can't open %s\\b", fname);
      exit(-1);
    }
    fprintf(fp, "<html>\\n<head>\\n<title>");
    fprintf(fp, "%s", name);
    fprintf(fp, "</title>\\n</head>\\n<body>\\n");
    fprintf(fp, "<p>name: %s</p>", name);
    fprintf(fp, "<canvas id=\\"vis\\" width=\\"%d\\" height=\\"%d\\"></canvas>", 2000,
            2000);
    fprintf(fp, "<script>\\n");
    fprintf(fp, "var vis = document.getElementById('vis');\\nvar ctx = "
                "vis.getContext('2d');\\n");

    rep(i, ss.size()) { fprintf(fp, "%s\\n", ss[i].c_str()); }

    fprintf(fp, "</script>\\n");
    fprintf(fp, "</body>\\n</html>\\n");
    fclose(fp);
  }

} makehtml_instance;

void addhtml(string s) { makehtml_instance.ss.push_back(s); }

void outhtml(string s, double mag) { makehtml_instance.out(s.c_str(), mag); }

void randcolhtml() {
  char ns[100];
  sprintf(ns, "ctx.fillStyle = \\"rgb(%d,%d,%d)\\";", rand() % 128, rand() % 128,
          rand() % 128);
  addhtml(ns);
  sprintf(ns, "ctx.strokeStyle = \\"rgb(%d,%d,%d)\\";", rand() % 128,
          rand() % 128, rand() % 128);
  addhtml(ns);
}

void inithtml() { makehtml_instance.ss.clear(); }

const double pi = 3.14159265358979;

struct pos {
  double x, y;
  double norm, norm2;
  pos tov(pos a) { return (a - (*this)); }
  pos operator+(pos a) const {
    pos res = a;
    res.x += x;
    res.y += y;
    res = pos(res.x, res.y);
    return res;
  }
  pos operator-(pos a) const {
    pos res = (*this);
    res.x -= a.x;
    res.y -= a.y;
    res = pos(res.x, res.y);
    return res;
  }
  pos scalar(double a) {
    pos res = (*this);
    res.x *= a;
    res.y *= a;
    res = pos(res.x, res.y);
    return res;
  }
  double dot(pos a) { return x * a.x + y * a.y; }
  double cross(pos a) { return x * a.y - y * a.x; }
  double theta(pos a) {
    double nt = dot(a) / (norm * a.norm);
    nt = acos(max(-1.0, min(1.0, nt)));
    double ns = (cross(a) / (norm * a.norm));
    if (ns < 0)
      nt *= -1;
    return nt;
  }
  pos(double ix, double iy) {
    x = ix;
    y = iy;
    norm2 = x * x + y * y;
    norm = sqrt(norm2);
  }
  pos() {}
  string str() {
    char ns[50];
    sprintf(ns, "(%lf %lf)", x, y);
    return string(ns);
  }
  void outh(double mag) {
    char ns[50];
    addhtml("ctx.beginPath();");
    sprintf(ns, "ctx.arc(%lf,%lf,%lf,0,360);", x * mag, y * mag, 5.0);
    addhtml(ns);
    addhtml("ctx.fill();");
  }
  static pos polar(double r, double t) { return pos(r * cos(t), r * sin(t)); }
  pos turn(double t) {
    // t[rad]??????
    return pos(x * cos(t) - y * sin(t), x * sin(t) + y * cos(t));
  }
  pos tolen(double a) {
    //?????????a?????????
    return this->scalar(a / norm);
  }
  bool operator<(pos a) const {
    // if(x!=a.x)return (x<a.x);
    // return (y<a.y);
    if (y != a.y)
      return (y < a.y);
    return (x < a.x);
  }
  bool operator>(pos a) const { return (a < (*this)); }
};
struct line {
  pos p, q;
  pos vec;
  string str() { return ("(" + p.str() + "-" + q.str() + ")"); }
  void outh(double mag) {
    char ns[50];
    addhtml("ctx.beginPath();");
    sprintf(ns, "ctx.moveTo(%lf,%lf);", p.x * mag, p.y * mag);
    addhtml(ns);
    sprintf(ns, "ctx.lineTo(%lf,%lf);", q.x * mag, q.y * mag);
    addhtml(ns);
    addhtml("ctx.stroke();");
  }
  bool iscross(line a) {
    double da, db;
    da = vec.cross(p.tov(a.p));
    db = vec.cross(p.tov(a.q));
    if (da * db >= 0)
      return false;
    da = a.vec.cross(a.p.tov(p));
    db = a.vec.cross(a.p.tov(q));
    return (da * db < 0);
  }
  line(pos ip, pos iq) {
    p = ip;
    q = iq;
    vec = p.tov(q);
  }
  line() {}
  double dist(pos a) {
    if (p.tov(a).dot(p.tov(q)) < 0)
      return p.tov(a).norm;
    if (q.tov(a).dot(q.tov(p)) < 0)
      return q.tov(a).norm;
    return abs(vec.cross(p.tov(a)) / vec.norm);
  }
  double dist(line a) {
    if (iscross(a))
      return 0;
    return min(min(dist(a.p), dist(a.q)),
               min(a.dist(this->p), a.dist(this->q)));
  }
  pos crosspos(line a) {
    /*
    double d1=a.vec.cross(a.p.tov(p))/a.vec.norm;
    double d2=a.vec.cross(a.p.tov(q))/a.vec.norm;
    bool isc=(d1*d2<0);
    d1=abs(d1); d2=abs(d2);
    double sc;
    if(!isc){
            if(d1>d2)sc = d1/(d1-d2);
            else sc=d1/(d2-d1);
    }
    else sc = d1/(d1+d2);
    return (p+vec.scalar(sc));*/

    double t = a.vec.cross(a.p - p) / a.vec.cross(vec);
    return (p + vec.scalar(t));
  }
  line bisection() { //?????´????????????
    //???????¨??????????90????????£???????????????
    pos fr = (p + q).scalar(0.5);
    pos to = fr + pos(-vec.y, vec.x);
    return line(fr, to);
  }
};
double lowofcos_getcos(double a, double b, double c) {
  return ((a * a + b * b - c * c) / (2 * a * b));
}
struct circle {
  pos p;
  double r;
  line koten(circle a) {
    pos cv = p.tov(a.p);
    double br = atan2(cv.y, cv.x);
    double dr = acos(lowofcos_getcos(r, cv.norm, a.r));
    pos p1 = p + pos::polar(r, br + dr);
    pos p2 = p + pos::polar(r, br - dr);
    if (p1 > p2)
      swap(p1, p2);
    return line(p1, p2);
  }
  circle(pos ip, double ir) {
    p = ip;
    r = ir;
  }
  circle() {}
  void outh(double mag) {
    char ns[50];
    addhtml("ctx.beginPath();");
    sprintf(ns, "ctx.arc(%lf,%lf,%lf,0,360);", p.x * mag, p.y * mag, r * mag);
    addhtml(ns);
    addhtml("ctx.stroke();");
  }

  vector<line> tangs(circle a) { //??\\?????????
    circle b(*this);
    if (a.r < b.r)
      swap(a, b);
    vector<line> res;
    if ((a.p - b.p).norm - (a.r - b.r) < 0.0)
      return res;
    if ((a.p - b.p).norm - (a.r - b.r) < 1e-6) {
      if ((b.p - a.p).norm < 1e-6)
        return res; //??¨???????????????
      pos rv = (b.p - a.p).tolen(a.r);
      res.push_back(line(rv + a.p, rv + a.p + rv.turn(pi / 2.0)));
      return res;
    }
    {
      pos cv = b.p - a.p;
      double th = acos((a.r - b.r) / cv.norm);
      pos p1 = cv.turn(th);
      res.push_back(line(a.p + p1.tolen(a.r), b.p + p1.tolen(b.r)));
      pos p2 = cv.turn(-th);
      res.push_back(line(a.p + p2.tolen(a.r), b.p + p2.tolen(b.r)));
    }
    if ((a.p - b.p).norm - (a.r + b.r) < 0.0)
      return res;
    if ((a.p - b.p).norm - (a.r + b.r) < 1e-6) {
      pos rv = (b.p - a.p).tolen(a.r);
      res.push_back(line(rv + a.p, rv + a.p + rv.turn(pi / 2.0)));
      return res;
    }
    {
      pos cv = b.p - a.p;
      double th = acos((a.r + b.r) / cv.norm);
      pos p1 = cv.turn(th);
      res.push_back(line(a.p + p1.tolen(a.r), b.p + p1.tolen(-b.r)));
      pos p2 = cv.turn(-th);
      res.push_back(line(a.p + p2.tolen(a.r), b.p + p2.tolen(-b.r)));
    }
    return res;
  }
};

struct polygon {
  vector<pos> ps;
  polygon() {}
  void outh(double mag) {
    char ns[50];
    addhtml("ctx.beginPath();");
    int ls = ps.size();
    sprintf(ns, "ctx.moveTo(%lf,%lf);", ps[ls - 1].x * mag, ps[ls - 1].y * mag);
    addhtml(ns);
    rep(i, ps.size()) {
      sprintf(ns, "ctx.lineTo(%lf,%lf);", ps[i].x * mag, ps[i].y * mag);
      addhtml(ns);
    }
    addhtml("ctx.stroke();");
  }
  double area() {
    double res = 0;
    rep(i, ps.size()) {
      pos no = ps[i], to = ps[(i + 1) % ps.size()];
      res += (no.x + to.x) * (no.y - to.y);
    }
    if (res < 0)
      reverse(ps.begin(), ps.end());
    return abs(res) / 2;
  }
  polygon(pos a, pos b) {
    ps.push_back(a);
    ps.push_back(pos(a.x, b.y));
    ps.push_back(b);
    ps.push_back(pos(b.x, a.y));
  }
  line gete(int a) {
    a %= ps.size();
    return line(ps[a], ps[(a + 1) % ps.size()]);
  }
  int isin(pos a) { //?????´??????2,?????£????????????1,?????????0
    double as = 0;
    rep(i, ps.size()) {
      line ne = gete(i);
      if (ne.dist(a) <= 0)
        return 1;
      pos v1 = a.tov(ne.p);
      pos v2 = a.tov(ne.q);
      as += v1.theta(v2);
    }
    if (abs(as) < 1e-6)
      return 0;
    return 2;
  }
  polygon convex_full() {
    polygon res;
    int ns = ps.size();
    vector<pos> vs(2 * ns);
    sort(ps.begin(), ps.end());
    int k = 0;
    rep(i, ns) {
      pos np = ps[i];
      while (k > 1 && vs[k - 2].tov(vs[k - 1]).cross(vs[k - 1].tov(np)) < -1e-6)
        k--;
      vs[k] = np;
      k++;
    }
    int t = k;
    ireg(i, 0, ns - 2) {
      pos np = ps[i];
      while (k > t && vs[k - 2].tov(vs[k - 1]).cross(vs[k - 1].tov(np)) < -1e-6)
        k--;
      vs[k] = np;
      k++;
    }
    vs.resize(k - 1);
    swap(vs, res.ps);
    return res;
  }
  polygon cut(line a) { //???????????????????????????
    polygon res;
    rep(i, ps.size()) {
      line ne = gete(i);
      double d1 = a.vec.cross(a.p.tov(ne.p));
      double d2 = a.vec.cross(a.p.tov(ne.q));
      if (d1 < 1e-6)
        res.ps.push_back(ne.p); //?????£????????£???eps
      if (d1 * d2 < -1e-6)
        res.ps.push_back(a.crosspos(ne)); //?????£????????????eps
    }
    return res;
  }

  vector<polygon> voronoi(vector<pos> ps) {
    // validate AOJ 2160
    vector<polygon> res;
    rep(i, ps.size()) {
      polygon np(*this);
      rep(j, ps.size()) {
        if (i == j)
          continue;
        line nl = line(ps[j], ps[i]).bisection();

        np = np.cut(nl);
      }
      res.push_back(np);
    }
    return res;
  }
  polygon mult(polygon a) { return a; }
};

int main(void) {
  for (;;) {
    int n;
    scanf("%d", &n);
    if (n == 0)
      break;
    vector<circle> cs;
    rep(i, n) {
      double x, y, r, m;
      scanf("%lf%lf%lf%lf", &x, &y, &r, &m);
      x += 10;
      y += 10;
      cs.push_back(circle(pos(x, y), r));
      cs.push_back(circle(pos(x, y), r + m));
    }
    if (n == 1) {
      printf("1\\n");
      continue;
    }

    int ans = 0;
    rep(i, 2 * n) {
      rep(j, i) {
        vector<line> ls = cs[i].tangs(cs[j]);
        rep(k, ls.size()) {
          // inithtml();
          line e = ls[k];
          e = line(e.p + e.vec.tolen(-3000), e.p + e.vec.tolen(3000));
          // e.outh(10);

          int na = 0;
          rep(p, n) {
            cs[p * 2].outh(10);
            cs[p * 2 + 1].outh(10);

            double d = e.dist(cs[p * 2].p);
            if (d + 1e-6 < cs[p * 2].r)
              continue;
            if (cs[p * 2 + 1].r + 1e-6 < d)
              continue;
            na++;
          }
          ans = max(ans, na);
          // printf("na %d %d %d %s %d\\n",i,j,k,e.str().c_str(),na);
          /*
          char buf[20];
          sprintf(buf,"o_%d_%d_%d",i,j,k);
          outhtml(buf,10);
          */
        }
      }
    }
    printf("%d\\n", ans);
  }
  return 0;
}