Problem p00910 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <algorithm>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

enum Type {
  UNKNOWN,
  YES,
  NO,
};

// 3次元
struct Point {
  Point(double arg_x, double arg_y, double arg_z) {
    x = arg_x;
    y = arg_y;
    z = arg_z;
  }

  Point() { x = y = z = 0.0; }

  Point operator+(Point p) { return Point(x + p.x, y + p.y, z + p.z); }
  Point operator-(Point p) { return Point(x - p.x, y - p.y, z - p.z); }
  Point operator*(double a) { return Point(a * x, a * y, a * z); }
  Point operator/(double a) { return Point(x / a, y / a, z / a); }

  double abs() { return sqrt(norm()); }
  double norm() { return x * x + y * y + z * z; }

  bool operator==(const Point &p) const {
    return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS && fabs(z - p.z) < EPS;
  }
  double x, y, z;
};

typedef Point Vector;

struct Line {
  Line(Point a, Point b) {
    p[0] = a;
    p[1] = b;
  }
  Point p[2];
};

struct Sphere {
  Point center;
  double r;
};

struct Data {
  Point center;
  double value;
};

int N, M, R;
int POW[16];
Sphere balloon[2000];
Data light[15];
Point E;
double memo[15][2000];
bool check[2000];

// 3次元
double norm(Vector a) { return a.x * a.x + a.y * a.y + a.z * a.z; }

double abs(Vector a) { return sqrt(norm(a)); }

double dot(Vector a, Vector b) { return a.x * b.x + a.y * b.y + a.z * b.z; }

double calc_value(int index) {
  return light[index].value /
         ((light[index].center.x - E.x) * (light[index].center.x - E.x) +
          (light[index].center.y - E.y) * (light[index].center.y - E.y) +
          (light[index].center.z - E.z) * (light[index].center.z - E.z));
}

// 垂線が引ける場合、交点を求める
Point projection(Line line, Point point) {
  double t = dot(point - line.p[0], line.p[0] - line.p[1]) /
             norm(line.p[0] - line.p[1]);
  return line.p[0] + (line.p[0] - line.p[1]) * t;
}

bool intersect(int light_index, int balloon_index) {

  if (memo[light_index][balloon_index] != UNKNOWN)
    return memo[light_index][balloon_index] == YES;

  Line line(light[light_index].center, E);

  Point a = line.p[0] - balloon[balloon_index]
                            .center, // balloonの中心と光源を結ぶ方向ベクトル
      b = line.p[1] - balloon[balloon_index]
                          .center, // balloonの中心と観測点を結ぶ方向ベクトル
      c = projection(line, balloon[balloon_index].center) -
          balloon[balloon_index]
              .center; // balloonの中心から、方向ベクトル()上に下した垂線ベクトル

  if (abs(a) < balloon[balloon_index].r - EPS &&
      abs(b) < balloon[balloon_index].r - EPS &&
      abs(c) < balloon[balloon_index].r - EPS) { // 内部に含まれる場合
    memo[light_index][balloon_index] = NO;
    return false;
  }
  if (abs(c) > balloon[balloon_index].r + EPS) { // 遠い場合
    memo[light_index][balloon_index] = NO;
    return false;
  }
  if (abs(a) < balloon[balloon_index].r - EPS ||
      abs(b) < balloon[balloon_index].r - EPS) {
    memo[light_index][balloon_index] = YES;
    return true;
  }
  if (abs(a - c) + abs(b - c) < abs(a - b) + EPS) {
    memo[light_index][balloon_index] = YES;
    return true;
  }
  memo[light_index][balloon_index] = NO;
  return false;
}

void func() {

  for (int i = 0; i < M; i++) {
    for (int k = 0; k < N; k++)
      memo[i][k] = UNKNOWN;
  }

  for (int i = 0; i < N; i++) {
    scanf("%lf %lf %lf %lf", &balloon[i].center.x, &balloon[i].center.y,
          &balloon[i].center.z, &balloon[i].r);
  }
  for (int i = 0; i < M; i++) {
    scanf("%lf %lf %lf %lf", &light[i].center.x, &light[i].center.y,
          &light[i].center.z, &light[i].value);
  }
  scanf("%lf %lf %lf", &E.x, &E.y, &E.z);

  double ans = 0.0, tmp_sum;
  int break_num;

  for (int state = POW[M]; state > 0;
       state--) { // 光を拾う光源の組み合わせを調べる
    break_num = 0;
    tmp_sum = 0.0;
    for (int loop = 0; loop < M; loop++) {
      if (state & (1 << loop)) {
        tmp_sum += calc_value(loop);
      }
    }
    if (tmp_sum <= ans)
      continue; // ansより小さいならSKIP

    tmp_sum = 0.0;
    for (int i = 0; i < N; i++)
      check[i] = false; // 割れたらtrue
    for (int loop = 0; loop < M; loop++) {
      if (state & (1 << loop)) { // 光源loopの光を拾う場合
        tmp_sum += calc_value(loop);
        // 交差する（割る）バルーンの数を数える
        for (int i = 0; i < N; i++) {
          if (check[i] == false && intersect(loop, i) == true) {
            break_num++;
            check[i] = true;
          }
        }

        if (break_num > R)
          break;
      }
    }
    if (break_num <= R) {
      ans = max(ans, tmp_sum);
    }
  }
  printf("%.10lf\\n", ans);
}

int main() {

  for (int i = 0; i < 16; i++)
    POW[i] = pow(2, i);

  while (true) {
    scanf("%d %d %d", &N, &M, &R);
    if (N == 0 && M == 0 && R == 0)
      break;

    func();
  }

  return 0;
}


Error: TLE

Fixed submission:

#include <algorithm>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

enum Type {
  UNKNOWN,
  YES,
  NO,
};

// 3次元
struct Point {
  Point(double arg_x, double arg_y, double arg_z) {
    x = arg_x;
    y = arg_y;
    z = arg_z;
  }

  Point() { x = y = z = 0.0; }

  Point operator+(Point p) { return Point(x + p.x, y + p.y, z + p.z); }
  Point operator-(Point p) { return Point(x - p.x, y - p.y, z - p.z); }
  Point operator*(double a) { return Point(a * x, a * y, a * z); }
  Point operator/(double a) { return Point(x / a, y / a, z / a); }

  double abs() { return sqrt(norm()); }
  double norm() { return x * x + y * y + z * z; }

  bool operator==(const Point &p) const {
    return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS && fabs(z - p.z) < EPS;
  }
  double x, y, z;
};

typedef Point Vector;

struct Line {
  Line(Point a, Point b) {
    p[0] = a;
    p[1] = b;
  }
  Point p[2];
};

struct Sphere {
  Point center;
  double r;
};

struct Data {
  Point center;
  double value;
};

int N, M, R;
int POW[16];
Sphere balloon[2000];
Data light[15];
Point E;
double memo[15][2000];
bool check[2000];

// 3次元
double norm(Vector a) { return a.x * a.x + a.y * a.y + a.z * a.z; }

double abs(Vector a) { return sqrt(norm(a)); }

double dot(Vector a, Vector b) { return a.x * b.x + a.y * b.y + a.z * b.z; }

double calc_value(int index) {
  return light[index].value /
         ((light[index].center.x - E.x) * (light[index].center.x - E.x) +
          (light[index].center.y - E.y) * (light[index].center.y - E.y) +
          (light[index].center.z - E.z) * (light[index].center.z - E.z));
}

// 垂線が引ける場合、交点を求める
Point projection(Line line, Point point) {
  double t = dot(point - line.p[0], line.p[0] - line.p[1]) /
             norm(line.p[0] - line.p[1]);
  return line.p[0] + (line.p[0] - line.p[1]) * t;
}

bool intersect(int light_index, int balloon_index) {

  if (memo[light_index][balloon_index] != UNKNOWN)
    return memo[light_index][balloon_index] == YES;

  Line line(light[light_index].center, E);

  Point a = line.p[0] - balloon[balloon_index]
                            .center, // balloonの中心と光源を結ぶ方向ベクトル
      b = line.p[1] - balloon[balloon_index]
                          .center, // balloonの中心と観測点を結ぶ方向ベクトル
      c = projection(line, balloon[balloon_index].center) -
          balloon[balloon_index]
              .center; // balloonの中心から、方向ベクトル()上に下した垂線ベクトル

  if (abs(a) < balloon[balloon_index].r - EPS &&
      abs(b) < balloon[balloon_index].r - EPS &&
      abs(c) < balloon[balloon_index].r - EPS) { // 内部に含まれる場合
    memo[light_index][balloon_index] = NO;
    return false;
  }
  if (abs(c) > balloon[balloon_index].r + EPS) { // 遠い場合
    memo[light_index][balloon_index] = NO;
    return false;
  }
  if (abs(a) < balloon[balloon_index].r - EPS ||
      abs(b) < balloon[balloon_index].r - EPS) {
    memo[light_index][balloon_index] = YES;
    return true;
  }
  if (abs(a - c) + abs(b - c) < abs(a - b) + EPS) {
    memo[light_index][balloon_index] = YES;
    return true;
  }
  memo[light_index][balloon_index] = NO;
  return false;
}

void func() {

  for (int i = 0; i < M; i++) {
    for (int k = 0; k < N; k++)
      memo[i][k] = UNKNOWN;
  }

  for (int i = 0; i < N; i++) {
    scanf("%lf %lf %lf %lf", &balloon[i].center.x, &balloon[i].center.y,
          &balloon[i].center.z, &balloon[i].r);
  }
  for (int i = 0; i < M; i++) {
    scanf("%lf %lf %lf %lf", &light[i].center.x, &light[i].center.y,
          &light[i].center.z, &light[i].value);
  }
  scanf("%lf %lf %lf", &E.x, &E.y, &E.z);

  double ans = 0.0, tmp_sum;
  int break_num;

  for (int state = 0; state < POW[M];
       state++) { // 光を拾う光源の組み合わせを調べる
    break_num = 0;
    tmp_sum = 0.0;
    for (int i = 0; i < N; i++)
      check[i] = false; // 割れたらtrue
    for (int loop = 0; loop < M; loop++) {
      if (state & (1 << loop)) { // 光源loopの光を拾う場合
        tmp_sum += calc_value(loop);
        // 交差する（割る）バルーンの数を数える
        for (int i = 0; i < N; i++) {
          if (check[i] == false && intersect(loop, i) == true) {
            break_num++;
            check[i] = true;
          }
        }

        if (break_num > R)
          break;
      }
    }
    if (break_num <= R) {
      ans = max(ans, tmp_sum);
    }
  }
  printf("%.10lf\\n", ans);
}

int main() {

  for (int i = 0; i < 16; i++)
    POW[i] = pow(2, i);

  while (true) {
    scanf("%d %d %d", &N, &M, &R);
    if (N == 0 && M == 0 && R == 0)
      break;

    func();
  }

  return 0;
}