Problem:
Problem J:
Castle Wall
A new lord assumed the position by the death of the previous lord in a Far Eastern province.
The new greedy lord hates concave polygons, because he believes they need much wasted area to be drawn on
paper. He always wants to modify them to convex ones.
His castle is currently surrounded by a wall forming a concave polygon, when seen from the above. Of course
he hates it. He believes more area could be obtained with a wall of a convex polygon. Thus he has ordered his
vassals to have new walls built so they form a convex polygon.
Unfortunately, there is a limit in the budget. So it might be infeasible to have the new walls built completely. The
vassals has found out that only up to r meters of walls in total can be built within the budget. In addition, the new
walls must be built in such a way they connect the polygonal vertices of the present castle wall. It is impossible
to build both of intersecting walls.
After long persuasion of the vassals, the new lord has reluctantly accepted that the new walls might not be built
completely. However, the vassals still want to maximize the area enclosed with the present and new castle walls,
so they can satisfy the lord as much as possible.
Your job is to write a program to calculate, for a given integer
r
, the maximum possible area of the castle with
the new walls.
Input
The input file contains several test cases.
Each case begins with a line containing two positive integers
n
and
r
.
n
is the number of vertices of the concave
polygon that describes the present castle wall, satisfying 5 ≤
n
≤ 64.
r
is the maximum total length of new castle
walls feasible within the budget, satisfying 0 ≤
r
≤ 400.
The subsequent
n
lines are the
x
- and
y
-coordinates of the n vertices. The line segments (
x
i
,
y
i
) - (
x
i
+1
,
y
i
+1
)
(1 ≤
i
≤
n
- 1) and (
x
n
,
y
n
) - (
x
1
,
y
1
) form the present castle wall of the concave polygon. Those coordinates are
given in meters and in the counterclockwise order of the vertices.
All coordinate values are integers between 0 and 100, inclusive. You can assume that the concave polygon is
simple, that is, the present castle wall never crosses or touches itself.
The last test case is followed by a line containing two zeros.
Output
For each test case in the input, print the case number (beginning with 1) and the maximum possible area enclosed
with the present and new castle walls. The area should be printed with exactly one fractional digit.
Sample Input
5 4
0 0
4 0
4 4
2 2
0 4
8 80
45 41
70 31
86 61
72 64
80 79
40 80
8 94
28 22
0 0
Output for the Sample Input
case 1: 16.0
case 2: 3375.0

Submitted solutions:

code_snippet: #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 !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;
typedef vector<Point> Polygon;

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

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) return m.p1; // same line
  if (abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!!
  return m.p1 +   (m.p2 - m.p1) * (B / A);
}

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

double angle(Point a,Point b,Point c) {
  double ux = b.x - a.x, uy = b.y - a.y;
  double vx = c.x - a.x, vy = c.y - a.y;
  return acos((ux*vx + uy*vy)/sqrt((ux*ux + uy*uy) * (vx*vx + vy*vy)));
}  
  
bool inPolygon(Polygon poly,Point p){
  if((int)poly.size() == 0)return false;
  rep(i,poly.size()) if(onSegment(poly[i],poly[(i+1)%poly.size()],p))return true;
  double sum = 0;
  for(int i=0; i < (int)poly.size() ;i++) {
    if( equals(cross(poly[i]-p,poly[(i+1)%poly.size()]-p),0.0) ) continue;
    if( cross3p(p,poly[i],poly[(i+1)%poly.size()]) < 0 ) sum -= angle(p,poly[i],poly[(i+1)%poly.size()]);
    else                                                 sum += angle(p,poly[i],poly[(i+1)%poly.size()]);
  }
  const double eps = 1e-6;
  return (fabs(sum - 2*M_PI) < eps || fabs(sum + 2*M_PI) < eps);
}  

Polygon andrewScan(Polygon s){
  Polygon u,l;
  if(s.size() < 3)return s;
  sort(s.begin(),s.end());
  u.push_back(s[0]); u.push_back(s[1]);
  l.push_back(s[s.size()-1]); l.push_back(s[s.size()-2]);

  for(int i=2;i<s.size();i++) {
    for(int n=u.size();n >= 2 && ccw(u[n-2],u[n-1],s[i]) != CLOCKWISE; n--) u.pop_back();
    u.push_back(s[i]);
  }

  for(int i=s.size()-3; i>=0 ; i--){
      for(int n=l.size(); n >= 2 && ccw(l[n-2],l[n-1],s[i]) != CLOCKWISE; n--) l.pop_back();
      l.push_back(s[i]);
  }
  reverse(l.begin(),l.end());
  for(int i = u.size()-2; i >= 1; i--) l.push_back(u[i]);
  return l;
}

bool inPolygon(const Polygon &poly,Segment seg){
  vector<Point> vp;
  vp.push_back(seg.p1);
  vp.push_back(seg.p2);
  rep(i,(int)poly.size()) {
    Segment edge = Segment(poly[i],poly[(i+1)%(int)poly.size()]);
    if( equals(cross(seg.p1-seg.p2,edge.p1-edge.p2),0.0) ) {
      if( onSegment(seg.p1,seg.p2,edge.p1) ) vp.push_back(edge.p1);
      if( onSegment(seg.p1,seg.p2,edge.p2) ) vp.push_back(edge.p2);
    } else {
      if( intersectSS(seg,edge) ) vp.push_back(crosspoint(seg,edge));
    }
  }
  sort(vp.begin(),vp.end());
  vp.erase(unique(vp.begin(),vp.end()),vp.end());
  rep(i,(int)vp.size()-1) {
    Point middle_point = ( vp[i] + vp[i+1] ) / 2.0;
    if( !inPolygon(poly,middle_point) ) return false;
  }
  return true;  
}

double getArea(const Polygon &poly){
  double sum = 0;
  rep(i,(int)poly.size()) sum += cross(poly[i],poly[(i+1)%(int)poly.size()]);
  return fabs(sum) * 0.5;
}

struct Edge {
  int dst,area;
  double length;
};

const double DINF = 1e30;

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

bool veri(const Polygon& poly,Segment seg) {
  rep(i,(int)poly.size()) {
    Segment edge = Segment(poly[i],poly[(i+1)%poly.size()]);
    if( edge == seg ) return false;
    vector<Point> vec;
    vec.push_back(seg.p1), vec.push_back(seg.p2), vec.push_back(edge.p1), vec.push_back(edge.p2);
    sort(vec.begin(),vec.end());
    vec.erase(unique(vec.begin(),vec.end()),vec.end());
    if( vec.size() == 3 ) continue;
    assert( vec.size() == 4);
    if( equals(cross(edge.p1-edge.p2,seg.p1-seg.p2),0.0) ) {
      if( onSegment(edge.p1,edge.p2,seg.p1) || onSegment(edge.p1,edge.p2,seg.p2) ||
          onSegment(seg.p1,seg.p2,edge.p1)  || onSegment(seg.p1,seg.p2,edge.p2) ) return false;
    } else {
      if( intersectSS(edge,seg) ) return false;
    }
  }
  return true;
}

int V;
Polygon poly;
double r;
const int LIMIT = 21000;
double dp[70][LIMIT+1];

vector<Edge> G[70];

void make_graph(){
  rep(i,poly.size()+1) G[i].clear();
  Polygon convex = andrewScan(poly);
  map<Point,int> mp;
  rep(i,(int)poly.size()) mp[poly[i]] = i;
  rep(i,(int)convex.size()) {
    int s = mp[convex[i]], t = mp[convex[(i+1)%(int)convex.size()]];
    if( (s+1)%V == t ) continue;
    for(int j=s;;(j+=1)%=V){
      for(int l=j;;(l+=1)%=V){
        if( j != l ){
          Segment seg = Segment(poly[j],poly[l]);
          if( !inPolygon(poly,seg) && veri(poly,seg) ) {
            vector<Point> vec;
            for(int k=j;;(k+=1)%=V) {
              vec.push_back(poly[k]);
              if( k == l ) break;
            }
            if( l ) G[min(j,l)].push_back((Edge){max(l,j),getArea(vec)*2,abs(poly[j]-poly[l])});
            else  G[j].push_back((Edge){V,getArea(vec)*2,abs(poly[j]-poly[l])});
          }
        }
        if( l == t ) break;
      }
      if( j == t ) break;
    }
  }
}

int CNT;

void compute(){
  make_graph();
  rep(i,V+1) rep(j,LIMIT+1) dp[i][j] = DINF;
  double maxi = getArea(poly);
  dp[0][(int)(maxi*2)] = 0;
  rep(i,V){
    rep(area,LIMIT)if( !equals(dp[i][area],DINF) ){
      rep(j,(int)G[i].size()){
        int next = G[i][j].dst;
        int cost = G[i][j].area;
        double length = G[i][j].length;
        if( area + cost < LIMIT && LT(dp[i][area]+length,dp[next][area+cost]) ) {
          dp[next][area+cost] = dp[i][area]+length;
        }
      }
    }
    rep(j,LIMIT) dp[i+1][j] = min(dp[i+1][j],dp[i][j]);
  }
  for(int i=LIMIT;i>=0;i--) if( !equals(dp[V][i],DINF) && LTE(dp[V][i],r) ) { 
      maxi = i * 0.5; break; 
    }
  printf("case %d: %.1f\n",CNT++,maxi);
}

int main(){
  int temp;
  CNT = 1;
  while( cin >> V >> temp, V|temp){
    r = temp;
    poly.clear();
    poly.resize(V);
    rep(i,V) cin >> poly[i].x >> poly[i].y;
    Point mini = poly[0];
    rep(i,V) mini = min(mini,poly[i]);
    int sp = -1;
    rep(i,V) if( mini == poly[i] ) { sp = i; break; }
    Polygon ps;
    for(int i=sp;i<V;i++) ps.push_back(poly[i]);
    for(int i=0;i<sp;i++) ps.push_back(poly[i]);
    poly = ps; 
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 12064
final_rank: 2

code_snippet: #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 !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;
typedef vector<Point> Polygon;

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

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) return m.p1; // same line
  if (abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!!
  return m.p1 +   (m.p2 - m.p1) * (B / A);
}

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

double angle(Point a,Point b,Point c) {
  double ux = b.x - a.x, uy = b.y - a.y;
  double vx = c.x - a.x, vy = c.y - a.y;
  return acos((ux*vx + uy*vy)/sqrt((ux*ux + uy*uy) * (vx*vx + vy*vy)));
}  
  
bool inPolygon(Polygon poly,Point p){
  if((int)poly.size() == 0)return false;
  rep(i,poly.size()) if(onSegment(poly[i],poly[(i+1)%poly.size()],p))return true;
  double sum = 0;
  for(int i=0; i < (int)poly.size() ;i++) {
    if( equals(cross(poly[i]-p,poly[(i+1)%poly.size()]-p),0.0) ) continue;
    if( cross3p(p,poly[i],poly[(i+1)%poly.size()]) < 0 ) sum -= angle(p,poly[i],poly[(i+1)%poly.size()]);
    else                                                 sum += angle(p,poly[i],poly[(i+1)%poly.size()]);
  }
  const double eps = 1e-6;
  return (fabs(sum - 2*M_PI) < eps || fabs(sum + 2*M_PI) < eps);
}  

Polygon andrewScan(Polygon s){
  Polygon u,l;
  if(s.size() < 3)return s;
  sort(s.begin(),s.end());
  u.push_back(s[0]); u.push_back(s[1]);
  l.push_back(s[s.size()-1]); l.push_back(s[s.size()-2]);

  for(int i=2;i<s.size();i++) {
    for(int n=u.size();n >= 2 && ccw(u[n-2],u[n-1],s[i]) != CLOCKWISE; n--) u.pop_back();
    u.push_back(s[i]);
  }

  for(int i=s.size()-3; i>=0 ; i--){
      for(int n=l.size(); n >= 2 && ccw(l[n-2],l[n-1],s[i]) != CLOCKWISE; n--) l.pop_back();
      l.push_back(s[i]);
  }
  reverse(l.begin(),l.end());
  for(int i = u.size()-2; i >= 1; i--) l.push_back(u[i]);
  return l;
}

bool inPolygon(const Polygon &poly,Segment seg){
  vector<Point> vp;
  vp.push_back(seg.p1);
  vp.push_back(seg.p2);
  rep(i,(int)poly.size()) {
    Segment edge = Segment(poly[i],poly[(i+1)%(int)poly.size()]);
    if( equals(cross(seg.p1-seg.p2,edge.p1-edge.p2),0.0) ) {
      if( onSegment(seg.p1,seg.p2,edge.p1) ) vp.push_back(edge.p1);
      if( onSegment(seg.p1,seg.p2,edge.p2) ) vp.push_back(edge.p2);
    } else {
      if( intersectSS(seg,edge) ) vp.push_back(crosspoint(seg,edge));
    }
  }
  sort(vp.begin(),vp.end());
  vp.erase(unique(vp.begin(),vp.end()),vp.end());
  rep(i,(int)vp.size()-1) {
    Point middle_point = ( vp[i] + vp[i+1] ) / 2.0;
    if( !inPolygon(poly,middle_point) ) return false;
  }
  return true;  
}

double getArea(const Polygon &poly){
  double sum = 0;
  rep(i,(int)poly.size()) sum += cross(poly[i],poly[(i+1)%(int)poly.size()]);
  return fabs(sum) * 0.5;
}

struct Edge {
  int dst,area;
  double length;
};

const double DINF = 1e30;

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

bool veri(const Polygon& poly,Segment seg) {
  rep(i,(int)poly.size()) {
    Segment edge = Segment(poly[i],poly[(i+1)%poly.size()]);
    if( edge == seg ) return false;
    vector<Point> vec;
    vec.push_back(seg.p1), vec.push_back(seg.p2), vec.push_back(edge.p1), vec.push_back(edge.p2);
    sort(vec.begin(),vec.end());
    vec.erase(unique(vec.begin(),vec.end()),vec.end());
    if( vec.size() == 3 ) continue;
    assert( vec.size() == 4);
    if( equals(cross(edge.p1-edge.p2,seg.p1-seg.p2),0.0) ) {
      if( onSegment(edge.p1,edge.p2,seg.p1) || onSegment(edge.p1,edge.p2,seg.p2) ||
          onSegment(seg.p1,seg.p2,edge.p1)  || onSegment(seg.p1,seg.p2,edge.p2) ) return false;
    } else {
      if( intersectSS(edge,seg) ) return false;
    }
  }
  return true;
}

int V;
Polygon poly;
double r;
const int LIMIT = 21000;
double dp[70][LIMIT+1];

vector<Edge> G[70];

void make_graph(){
  rep(i,poly.size()+1) G[i].clear();
  Polygon convex = andrewScan(poly);
  map<Point,int> mp;
  rep(i,(int)poly.size()) mp[poly[i]] = i;
  rep(i,(int)convex.size()) {
    int s = mp[convex[i]], t = mp[convex[(i+1)%(int)convex.size()]];
    if( (s+1)%V == t ) continue;
    for(int j=s;;(j+=1)%=V){
      for(int l=j;;(l+=1)%=V){
        if( j != l ){
          Segment seg = Segment(poly[j],poly[l]);
          if( !inPolygon(poly,seg) && veri(poly,seg) ) {
            vector<Point> vec;
            for(int k=j;;(k+=1)%=V) {
              vec.push_back(poly[k]);
              if( k == l ) break;
            }
            if( l ) G[min(j,l)].push_back((Edge){max(l,j),getArea(vec)*2,abs(poly[j]-poly[l])});
            else  G[j].push_back((Edge){V,getArea(vec)*2,abs(poly[j]-poly[l])});
          }
        }
        if( l == t ) break;
      }
      if( j == t ) break;
    }
  }
}

int CNT;

void compute(){
  make_graph();
  rep(i,V+1) rep(j,LIMIT+1) dp[i][j] = DINF;
  
  Polygon convex = andrewScan(poly);

  set<Point> temp_S;
  rep(i,(int)convex.size()) temp_S.insert(convex[i]);
  double maxi = getArea(poly);
  dp[0][(int)(maxi*2)] = 0;
  rep(i,V){
    rep(area,LIMIT)if( !equals(dp[i][area],DINF) ){
      rep(j,(int)G[i].size()){
        int next = G[i][j].dst;
        int cost = G[i][j].area;
        double length = G[i][j].length;
        if( area + cost < LIMIT && LT(dp[i][area]+length,dp[next][area+cost]) ) {
          dp[next][area+cost] = dp[i][area]+length;
        }
      }
    }
    rep(j,LIMIT) dp[i+1][j] = min(dp[i+1][j],dp[i][j]);
  }
  for(int i=LIMIT;i>=0;i--) if( !equals(dp[V][i],DINF) && LTE(dp[V][i],r) ) { 
      maxi = i * 0.5; break; 
    }
  printf("case %d: %.1f\n",CNT++,maxi);
}

int main(){
  int temp;
  CNT = 1;
  while( cin >> V >> temp, V|temp){
    r = temp;
    poly.clear();
    poly.resize(V);
    rep(i,V) cin >> poly[i].x >> poly[i].y;
    Point mini = poly[0];
    rep(i,V) mini = min(mini,poly[i]);
    int sp = -1;
    rep(i,V) if( mini == poly[i] ) { sp = i; break; }
    Polygon ps;
    for(int i=sp;i<V;i++) ps.push_back(poly[i]);
    for(int i=0;i<sp;i++) ps.push_back(poly[i]);
    poly = ps; 
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 12060
final_rank: 1

code_snippet: #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);}
  Point operator * (Point a){ return Point(x * a.x - y * a.y, x * a.y + y * a.x); }

  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;
typedef vector<Point> Polygon;

ostream& operator << (ostream& os,const Point& a){ os << "(" << a.x << "," << a.y << ")"; }

ostream& operator << (ostream& os,const Segment& a){ os << "( " << a.p1 << " , " << a.p2 << " )"; }

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

//rad は角度をラジアンで持たせること
Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }

// 度をラジアンに変換
double toRad(double agl){ return agl*M_PI/180.0; }

// a => prev, b => cur, c=> next
// prev から cur へ行って next へ行く際の角度を求める
double getArg(Point a,Point b,Point c){
  double arg1 = atan2(b.y-a.y,b.x-a.x);
  double arg2 = atan2(c.y-b.y,c.x-b.x);
  double arg = fabs( arg1 - arg2 );
  while( arg > M_PI ) arg -= 2.0 * M_PI;
  return fabs(arg);
}

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 intersectLL(Line l, Line m) {
  return abs(cross(l.p2-l.p1, m.p2-m.p1)) > EPS || // non-parallel
         abs(cross(l.p2-l.p1, m.p1-l.p1)) < EPS;   // same line
}
bool intersectLS(Line l, Line s) {
  return cross(l.p2-l.p1, s.p1-l.p1)*       // s[0] is left of l
         cross(l.p2-l.p1, s.p2-l.p1) < EPS; // s[1] is right of l
}
bool intersectLP(Line l,Point p) {
  return abs(cross(l.p2-p, l.p1-p)) < EPS;
}
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; // triangle inequality
}

Point projection(Line l,Point p) {
  double t = dot(p-l.p1, l.p1-l.p2) / norm(l.p1-l.p2);
  return l.p1 + (l.p1-l.p2)*t;
}
Point reflection(Line l,Point p) {
  return p + (projection(l, p) - p) * 2;
}
double distanceLP(Line l, Point p) {
  return abs(p - projection(l, p));
}
double distanceLL(Line l, Line m) {
  return intersectLL(l, m) ? 0 : distanceLP(l, m.p1);
}

double distanceLS(Line l, Line s) {
  if (intersectLS(l, s)) return 0;
  return min(distanceLP(l, s.p1), distanceLP(l, s.p2));
}
double distanceSP(Line s, Point p) {
  Point r = projection(s, p);
  if (intersectSP(s, r)) return abs(r - p);
  return min(abs(s.p1 - p), abs(s.p2 - p));
}

double distanceSS(Line s, Line t) {
  if (intersectSS(s, t)) return 0;
  return min(min(distanceSP(s, t.p1), distanceSP(s, t.p2)),
             min(distanceSP(t, s.p1), distanceSP(t, s.p2)));
}

/*
same lineの時注意
もしm.p1が中心でなかったときに正しい答えとならない
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());
    assert(vec[1] == vec[2]); //同じセグメントかもよ
    return vec[1];
    //return m.p1;
  }
  if(abs(A) < EPS)assert(false);
  return m.p1 + (m.p2-m.p1)*(B/A);
}

*/
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) return m.p1; // same line
  if (abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!!
  return m.p1 +   (m.p2 - m.p1) * (B / A);
}

//cross product of pq and pr
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); }
  
//returns true if point r is on the same line as the line pq
bool collinear(Point p,Point q,Point r) { return fabs(cross3p(p,q,r)) < EPS; }
  
//returns true if point t is on the left side of line pq
bool ccwtest(Point p,Point q,Point r){
  return cross3p(p,q,r) > 0; //can be modified to accept collinear points
}
 
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 isConvex(vector<Point> p) {
  int sz = (int)p.size();
  if(sz < 3)return false;//boundary case, we treat a point or a line as not convex
  bool isLeft = ccwtest(p[0],p[1],p[2]);
  for(int i=1; i<(int)p.size();i++)
    if(ccwtest(p[i],p[(i+1)%sz],p[(i+2)%sz]) != isLeft) return false;
  return true;
}


double angle(Point a,Point b,Point c) {
  double ux = b.x - a.x, uy = b.y - a.y;
  double vx = c.x - a.x, vy = c.y - a.y;
  return acos((ux*vx + uy*vy)/sqrt((ux*ux + uy*uy) * (vx*vx + vy*vy)));
}  
  
//多角形poly内（線分上も含む）に点pが存在するかどうは判定する  
bool inPolygon(Polygon poly,Point p){
  if((int)poly.size() == 0)return false;
  rep(i,poly.size()) if(onSegment(poly[i],poly[(i+1)%poly.size()],p))return true;
  double sum = 0;
  for(int i=0; i < (int)poly.size() ;i++) {
    if( equals(cross(poly[i]-p,poly[(i+1)%poly.size()]-p),0.0) ) continue; // ３点が平行だとangleがnanを返しsumがnanになり死ぬ
    if( cross3p(p,poly[i],poly[(i+1)%poly.size()]) < 0 ) sum -= angle(p,poly[i],poly[(i+1)%poly.size()]);
    else                                                 sum += angle(p,poly[i],poly[(i+1)%poly.size()]);
  }
  // あまり誤差を厳しくしすぎると良くないので以下のほうが良い 
  const double eps = 1e-6;
  return (fabs(sum - 2*M_PI) < eps || fabs(sum + 2*M_PI) < eps);
}  


Polygon andrewScan(Polygon s){
  Polygon u,l;
  if(s.size() < 3)return s;
  sort(s.begin(),s.end());
  u.push_back(s[0]); u.push_back(s[1]);
  l.push_back(s[s.size()-1]); l.push_back(s[s.size()-2]);

  for(int i=2;i<s.size();i++) {
    for(int n=u.size();n >= 2 && ccw(u[n-2],u[n-1],s[i]) != CLOCKWISE; n--) u.pop_back();
    u.push_back(s[i]);
  }

  for(int i=s.size()-3; i>=0 ; i--){
      for(int n=l.size(); n >= 2 && ccw(l[n-2],l[n-1],s[i]) != CLOCKWISE; n--) l.pop_back();
      l.push_back(s[i]);
  }
  reverse(l.begin(),l.end());
  for(int i = u.size()-2; i >= 1; i--) l.push_back(u[i]);
  return l;
}


bool inPolygon(const Polygon &poly,Segment seg){
  vector<Point> vp;
  vp.push_back(seg.p1);
  vp.push_back(seg.p2);
  rep(i,(int)poly.size()) {
    Segment edge = Segment(poly[i],poly[(i+1)%(int)poly.size()]);
    if( equals(cross(seg.p1-seg.p2,edge.p1-edge.p2),0.0) ) {
      if( onSegment(seg.p1,seg.p2,edge.p1) ) vp.push_back(edge.p1);
      if( onSegment(seg.p1,seg.p2,edge.p2) ) vp.push_back(edge.p2);
    } else {
      if( intersectSS(seg,edge) ) vp.push_back(crosspoint(seg,edge));
    }
  }
  sort(vp.begin(),vp.end());
  vp.erase(unique(vp.begin(),vp.end()),vp.end());
  rep(i,(int)vp.size()-1) {
    Point middle_point = ( vp[i] + vp[i+1] ) / 2.0;
    if( !inPolygon(poly,middle_point) ) return false;
  }
  return true;  
}

double getArea(const Polygon &poly){
  double sum = 0;
  rep(i,(int)poly.size()) sum += cross(poly[i],poly[(i+1)%(int)poly.size()]);
  return fabs(sum) * 0.5;
}


struct Edge {
  int dst,area;
  double length;
};

const double DINF = 1e30;

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

bool veri(const Polygon& poly,Segment seg) {
  rep(i,(int)poly.size()) {
    Segment edge = Segment(poly[i],poly[(i+1)%poly.size()]);
    if( edge == seg ) return false;
    vector<Point> vec;
    vec.push_back(seg.p1), vec.push_back(seg.p2), vec.push_back(edge.p1), vec.push_back(edge.p2);
    sort(vec.begin(),vec.end());
    vec.erase(unique(vec.begin(),vec.end()),vec.end());
    if( vec.size() == 3 ) continue;
    assert( vec.size() == 4);
    if( equals(cross(edge.p1-edge.p2,seg.p1-seg.p2),0.0) ) {
      if( onSegment(edge.p1,edge.p2,seg.p1) || onSegment(edge.p1,edge.p2,seg.p2) ||
          onSegment(seg.p1,seg.p2,edge.p1)  || onSegment(seg.p1,seg.p2,edge.p2) ) return false;
    } else {
      if( intersectSS(edge,seg) ) return false;
    }
  }
  return true;
}

int V;
Polygon poly;
double r;
const int LIMIT = 21000;
double dp[70][LIMIT+1];

vector<Edge> G[70];

void make_graph(){
  rep(i,poly.size()+1) G[i].clear();
  Polygon convex = andrewScan(poly);
  map<Point,int> mp;
  rep(i,(int)poly.size()) mp[poly[i]] = i;
  /*
  cout << "convex ---- " << endl;
  rep(i,(int)convex.size()) cout << poly[mp[convex[i]]] << " "; cout << endl;
  */
  rep(i,(int)convex.size()) {
    int s = mp[convex[i]], t = mp[convex[(i+1)%(int)convex.size()]];
    //cout << s << " " << t << endl;
    if( (s+1)%V == t ) continue;
    for(int j=s;;(j+=1)%=V){
      for(int l=j;;(l+=1)%=V){
        if( j != l ){
          Segment seg = Segment(poly[j],poly[l]);
          if( !inPolygon(poly,seg) && veri(poly,seg) ) {
            vector<Point> vec;
            for(int k=j;;(k+=1)%=V) {
              vec.push_back(poly[k]);
              if( k == l ) break;
            }
            //cout << "add " << j << " to " << l << " ||| " << seg<< endl;
            //G[j].push_back((Edge){l,abs(poly[j]-poly[l]),getArea(vec)});
            if( l ) G[min(j,l)].push_back((Edge){max(l,j),getArea(vec)*2,abs(poly[j]-poly[l])});
            else {
              /* 
                 poly の最後に先頭をくっつけるとこんな処理しなくても良いかも?
              */
              G[j].push_back((Edge){V,getArea(vec)*2,abs(poly[j]-poly[l])});
            }
            //G[l].push_back((Edge){j,abs(poly[j]-poly[l]),getArea(vec)});
          }
        }
        if( l == t ) break;
      }
      if( j == t ) break;
    }
  }
  /*
  rep(i,V) for(int j=(i+1)%V;j!=i;(j+=1)%=V){
    if( min(i,j)+1 == max(i,j) ) continue;
    Segment seg = Segment(poly[i],poly[j]);
    if( inPolygon(poly,seg) ) continue;
    vector<Point> vec;
    int sp,ep;
    if( i && j && i < j ) { sp = i, ep = j; }
    else                  { sp = max(i,j), ep = min(i,j); }
    for(int k=sp;;(k+=1)%=V) {
      vec.push_back(poly[k]);
      if( k == ep ) break;
    }
    G[i].push_back((Edge){j,abs(poly[i]-poly[j]),getArea(vec)});
  }
  */
}

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

int CNT;

void compute(){

  make_graph();
  /*
  cout << endl;
  cout << "made graph" << endl;
  rep(i,V) {
    cout << i << "-th " << poly[i] << endl;
    rep(j,(int)G[i].size()) {
      cout << "(" << G[i][j].dst << "=>" << poly[G[i][j].dst] << ", " << G[i][j].length << "," << G[i][j].area << endl;
    }
  } cout << endl;
  */
  rep(i,V+1) rep(j,LIMIT+1) dp[i][j] = DINF;
  
  Polygon convex = andrewScan(poly);

  set<Point> temp_S;
  rep(i,(int)convex.size()) temp_S.insert(convex[i]);
  /*
  int sp = -1;
  //rep(i,(int)poly.size()) if( temp_S.count(poly[i]) ) { sp = i; break; }
  for(int i=(int)poly.size()-1;i>=0;i--)if( temp_S.count(poly[i]) ) { sp = i; break; }
  assert( sp != -1);
  */
  double maxi = getArea(poly);
  //cout << "first area = " << maxi << endl;
  //rep(i,V) dp[i][(int)r*100] = maxi;
  dp[0][(int)(maxi*2)] = 0;
  rep(i,V){
    rep(area,LIMIT)if( !equals(dp[i][area],DINF) ){
      rep(j,(int)G[i].size()){
        int next = G[i][j].dst;
        int cost = G[i][j].area;
        double length = G[i][j].length;
        if( area + cost < LIMIT && LT(dp[i][area]+length,dp[next][area+cost]) ) {
          dp[next][area+cost] = dp[i][area]+length;
        }
      }
    }
    rep(j,LIMIT) dp[i+1][j] = min(dp[i+1][j],dp[i][j]);
  }
  for(int i=LIMIT;i>=0;i--) if( !equals(dp[V][i],DINF) && LTE(dp[V][i],r) ) { 
      //cout << dp[V][i] << " " << r << endl;
      maxi = i * 0.5; break; 
    }
  /*
  for(int i=sp;;(i+=1)%=V){
    for(int j=LIMIT;j>=0;j--) if( !equals(dp[i][j],-DINF) ){
      rep(k,(int)G[i].size()){
        int dst = G[i][k].to;
        double cons = G[i][k].consumption;
        int icons = cons * 100.0;
        double area = G[i][k].area;


        if( LT(r,(double)j/100.0 - cons) ) continue;
        if( j - icons < 0 ) continue;
        cout << dp[dst][j-icons] << " < " << dp[i][j] + area << endl;
        if( LT(dp[dst][j-icons],dp[i][j]+area) ) {
          dp[dst][j-icons] = dp[i][j] + area;
          maxi = max(maxi,dp[dst][j-icons]);
        }
      }
    }
    rep(j,LIMIT+1) dp[(i+1)%V][j] = max(dp[(i+1)%V][j],dp[i][j]);
    if( i == ((sp-1+V)%V) ) break;
  }
  */
  printf("case %d: %.1f\n",CNT++,maxi);
}

int main(){
  int temp;
  CNT = 1;
  while( cin >> V >> temp, V|temp){
    r = temp;
    poly.clear();
    poly.resize(V);
    rep(i,V) cin >> poly[i].x >> poly[i].y;
    Point mini = poly[0];
    rep(i,V) mini = min(mini,poly[i]);
    int sp = -1;
    rep(i,V) if( mini == poly[i] ) { sp = i; break; }
    assert( sp != -1 );
    Polygon ps;
    for(int i=sp;i<V;i++) ps.push_back(poly[i]);
    for(int i=0;i<sp;i++) ps.push_back(poly[i]);
    poly = ps; 
    //rep(i,poly.size()) cout << poly[i] << endl;
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 12064
final_rank: 2

code_snippet: #include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <cmath>
#include <algorithm>

using namespace std;

const int N = 66;
const int M = 40000 + 10;
const int O = 20000 + 5;
const long double INF = 1e10;

int n, r;
int st, test;
int x[N], y[N];
int nx[N], ny[N];
bool ok[N][N];
long double f[N][M];

int sign(int x)
{
	return x < 0 ? -1 : x > 0;
}

int xmult(int p1, int p2, int q)
{
	return sign((x[p1] - x[q]) * (y[p2] - y[q]) - (x[p2] - x[q]) * (y[p1] - y[q]));
}

int on(int p1, int p2, int q)
{
	if (xmult(p1, p2, q)) return false;
	return (x[p1] - x[q]) * (x[p2] - x[q]) + (y[p1] - y[q]) * (y[p2] - y[q]) < 0;
}

int xmult(int p1, int p2)
{
	return x[p1] * y[p2] - x[p2] * y[p1];
}

int intersect(int p1, int p2, int q1, int q2)
{
	return xmult(p1, p2, q1) * xmult(p1, p2, q2) < 0 && xmult(q1, q2, p1) * xmult(q1, q2, p2) < 0;
}

void update(long double &a, long double b)
{
	if (a > b) a = b;
}

long double dis(int u, int v)
{
	return hypot(x[u] - x[v], y[u] - y[v]);
}

void solve()
{
	st = 0;
	for(int i = 0; i < n; ++ i) {
		cin >> x[i] >> y[i];
		if (x[i] < x[st]) {
			st = i;
		}
	}
	for(int i = 0; i < n; ++ i) {
		nx[i] = x[(i + st) % n];
		ny[i] = y[(i + st) % n];
	}
	for(int i = 0; i < n; ++ i) {
		x[i] = nx[i];
		y[i] = ny[i];
	}
	x[n] = x[0];
	y[n] = y[0];

	memset(ok, 0, sizeof ok);
	for(int i = 0; i < n; ++ i) {
		for(int j = i + 2; j <= n; ++ j) {
			if (i == 0 && j == n) continue;
			bool flag = true;
			{
				for(int k = 0; k < n; ++ k) {
					if (k == i || k == j % n) continue;
					if (on(i, j, k)) {
						flag = false;
						break;
					}
				}
			}
			if (flag) {
				for(int k = 0; k < n; ++ k) {
					if (intersect(i, j, k, k + 1)) {
						flag = false;
						break;
					}
				}
			}
			if (flag) {
				int area = xmult(i, j);
				for(int k = j - 1; k >= i; -- k) {
					area += xmult(k + 1, k);
				}
				if (area <= 0) flag = false;
			}
			ok[i][j] = flag;
		}
	}

	for(int i = 0; i <= n; ++ i) {
		for(int j = 0; j < M; ++ j) {
			f[i][j] = INF;
		}
	}
	f[0][O] = 0;

	for(int i = 0; i < n; ++ i) {
		for(int j = 0; j < M; ++ j) {
			if (f[i][j] >= INF) continue;
			update(f[i + 1][j + xmult(i, i + 1)], f[i][j]);
			for(int k = i + 2; k <= n; ++ k) {
				if (ok[i][k]) {
					update(f[k][j + xmult(i, k)], f[i][j] + dis(i, k));
				}
			}
		}
	}

	int ret = 0;
	for(int i = O; i < M; ++ i) {
		if (f[n][i] - 1e-8 > r) continue;
		ret = i - O;
	}
	if (ret & 1)
		printf("%d.5\n", ret >> 1);
	else
		printf("%d.0\n", ret >> 1);
}

int main()
{
	test = 0;
	for( ; cin >> n >> r && (n || r); ) {
		printf("case %d: ", ++ test);
		solve();
	}
	return 0;
}
accuracy: 1
time_ms: 390
memory_kb: 42120
final_rank: 6

code_snippet: #include<iostream>
#include<cstdlib>
#include<cmath>
#include<complex>
#include<vector>
#include<algorithm>
#include<cassert>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define pb         push_back

typedef complex<int> P;
const double eps= 1e-10;
const int N =200;
int cross(P a,P b){//ll?
  return a.real()*b.imag()-a.imag()*b.real();
}

//ê¼üÌf[^ðÈ­Í<0,È«½­È¢Í<=0É·éÆ¢¢B
int ccw(P a,P b){
  if ( cross(a,b) <0)return 1;
  else return -1;
}

bool cmp(const P&a,const P&b){
  if ( a.real() != b.real())return a.real()<b.real();
  else return a.imag() < b.imag();
}

void ConvexHull(int n,P *inp,P *out,int &p){
  sort(inp,inp+n,cmp);
  bool used[n];
  int num[n];
  fill(used,used+n,false);
  p=0;
  out[p++]=inp[0];out[p++]=inp[1];
  used[1]=true;
  num[0]=0;num[1]=1;
  for(int i=2;i<n;i++){
    while(p>=2){
      if ( ccw(out[p-1]-out[p-2],inp[i]-out[p-2]) ==1)break;
      else {
	used[num[p-1]]=false;
	p--;
      }
    }
    num[p]=i;
    used[i]=true;
    out[p++]=inp[i];
  }
  for(int i=n-2,t=p+1;i>=0;i--){
    if ( used[i] == true)continue;
    while(p>=t){//·ÅÉÊïÉÈÁ½_ðÁ³È¢æ¤É·éB
      if ( ccw(out[p-1]-out[p-2],inp[i]-out[p-2]) ==1)break;
      else p--;
    }
    out[p++]=inp[i];
  }
  return;
}

int polygon_area(const P *a,int n){
  int sum = 0;
  for(int i=0;i<n;i++){
    sum += (a[i%n].real()-a[(i+1)%n].real())*(a[i%n].imag()+a[(i+1)%n].imag());
  }
  
  //if (sum < 0)sum=-sum;
  return sum;
}

double dist(P a){
  complex<double> ho((double)a.real(),(double)a.imag());
  return abs(ho);
  return sqrt((double)a.real()*a.real()+(double)a.imag()*a.imag());
}

bool isp(P a,P b,P c){
  return dist(a-c)+dist(b-c) < dist(a-b)+eps;
}

bool is_intersected_ls(P a1,P a2,P b1,P b2){
  if ((cross(a2-a1,b1-a1)*cross(a2-a1,b2-a1)<0 ) && 
      (cross(b2-b1,a1-b1)*cross(b2-b1,a2-b1)<0))return true;
  else return false;
}

class Edge{
public:
  int num;
  double dist;
  int val;
};
vector<Edge>edge[N];

const int M = 20010;
double dp[N][M];

int solve(int n,P *in,double r,int lim){
  if (r==0)return 0;

  rep(i,n){
    REP(j,i+2,n+1){
      bool isok=true;
      if (!isok)continue;
      rep(k,n+1){
	if (k%n==i||(k+1)%n==i||
	    k%n==j||(k+1)%n==j)continue;
      	if (is_intersected_ls(in[i],in[j],in[k],in[k+1])){isok=false;break;}
      }
      if (!isok)continue;
      int tmp = polygon_area(in+i,j-i+1);
      if( tmp > 0)continue;
      tmp=-tmp;
      if (i == 0  && j == n)continue;
      edge[i].pb((Edge){j,dist(in[i]-in[j]),tmp});
    }
  }
  
  rep(i,n+1){
    rep(j,M)dp[i][j]=1e20;
    dp[i][0]=0;
  }

  rep(i,n){
    rep(j,M){
      if (i)dp[i][j]=min(dp[i][j],dp[i-1][j]);
      rep(k,edge[i].size()){
	int nexi=edge[i][k].num;
	int nexj=j+edge[i][k].val;
	double nev=dp[i][j]+edge[i][k].dist;
	if (nexj >= M)continue;
	dp[nexi][nexj]=min(dp[nexi][nexj],nev);
      }
    }
  }
  
  int ans = 0;
  for(int j=M-1;j>0;j--){
    rep(i,n+1){
      if (dp[i][j] <= r+eps){return j;}
    }
  }
  return 0;
}

main(){
  int n,r;
  int tc=1;
  P tmp[N],hoge[N],in[N],out[N];
  while(cin>>n>>r && n){
    int p=0;
    int ans=0;
    rep(i,N)edge[i].clear();
    
    rep(i,n){
      int x,y;
      cin>>x>>y;
      tmp[i]=P(x,y);
      hoge[i]=tmp[i];
    }
    ans = polygon_area(hoge,n);
    ConvexHull(n,hoge,out,p);
    int lim=polygon_area(out,p);
    
    int move=-1;
    rep(i,n){
      if (out[0] == tmp[i]){
	move=i;
	break;
      }
    }
    rep(i,n){
      in[i]=tmp[(i+move)%n];
    }
    tmp[n]=tmp[0];
    in[n]=in[0];
    rep(i,n)in[n+i]=in[i];
    rep(i,n)tmp[n+i]=tmp[i];
    
    ans+=solve(n,in,(double)r,lim-ans);
    printf("case %d: %.1lf\n",tc++,ans/2.);
  }
}
accuracy: 1
time_ms: 630
memory_kb: 10000
final_rank: 4

code_snippet: #include<iostream>
#include<cstdlib>
#include<cmath>
#include<complex>
#include<vector>
#include<algorithm>
#include<cassert>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define pb         push_back

typedef complex<int> P;
const double eps= 1e-10;
const int N =200;
int cross(P a,P b){//ll?
  return a.real()*b.imag()-a.imag()*b.real();
}

//ê¼üÌf[^ðÈ­Í<0,È«½­È¢Í<=0É·éÆ¢¢B
int ccw(P a,P b){
  if ( cross(a,b) <0)return 1;
  else return -1;
}

bool cmp(const P&a,const P&b){
  if ( a.real() != b.real())return a.real()<b.real();
  else return a.imag() < b.imag();
}

void ConvexHull(int n,P *inp,P *out,int &p){
  sort(inp,inp+n,cmp);
  bool used[n];
  int num[n];
  fill(used,used+n,false);
  p=0;
  out[p++]=inp[0];out[p++]=inp[1];
  used[1]=true;
  num[0]=0;num[1]=1;
  for(int i=2;i<n;i++){
    while(p>=2){
      if ( ccw(out[p-1]-out[p-2],inp[i]-out[p-2]) ==1)break;
      else {
	used[num[p-1]]=false;
	p--;
      }
    }
    num[p]=i;
    used[i]=true;
    out[p++]=inp[i];
  }
  for(int i=n-2,t=p+1;i>=0;i--){
    if ( used[i] == true)continue;
    while(p>=t){//·ÅÉÊïÉÈÁ½_ðÁ³È¢æ¤É·éB
      if ( ccw(out[p-1]-out[p-2],inp[i]-out[p-2]) ==1)break;
      else p--;
    }
    out[p++]=inp[i];
  }
  return;
}

int polygon_area(const P *a,int n){
  int sum = 0;
  for(int i=0;i<n;i++){
    sum += (a[i%n].real()-a[(i+1)%n].real())*(a[i%n].imag()+a[(i+1)%n].imag());
  }
  
  //if (sum < 0)sum=-sum;
  return sum;
}

double dist(P a){
  complex<double> ho((double)a.real(),(double)a.imag());
  return abs(ho);
  return sqrt((double)a.real()*a.real()+(double)a.imag()*a.imag());
}

bool isp(P a,P b,P c){
  return dist(a-c)+dist(b-c) < dist(a-b)+eps;
}

bool is_intersected_ls(P a1,P a2,P b1,P b2){
  //if (isp(a1,a2,b1))return true;
  //if (isp(a1,a2,b2))return true;
  //if (isp(b1,b2,a1))return true;
  //if (isp(b1,b2,a2))return true;
  if ((cross(a2-a1,b1-a1)*cross(a2-a1,b2-a1)<0 ) && 
      (cross(b2-b1,a1-b1)*cross(b2-b1,a2-b1)<0))return true;
  else return false;
}

class Edge{
public:
  int num;
  double dist;
  int val;
};
vector<Edge>edge[N];

const int M = 20010;
double dp[N][M];

int solve(int n,P *in,double r,int lim){
  if (r==0)return 0;

  rep(i,n){
    REP(j,i+2,n+1){
      bool isok=true;
//       for(int k=i+1;k<j;k++){
// 	if (isp(in[i],in[j],in[k])||
// 	    ccw(in[j]-in[i],in[k]-in[i])==1){isok=false;break;}
//       }
      if (!isok)continue;
      //      for(int k=i+1;k+1<j;k++){
      rep(k,n+1){
	if (k%n==i||(k+1)%n==i||
	    k%n==j||(k+1)%n==j)continue;
      	if (is_intersected_ls(in[i],in[j],in[k],in[k+1])){isok=false;break;}
      }
      if (!isok)continue;
      int tmp = polygon_area(in+i,j-i+1);
      if( tmp > 0)continue;
      tmp=-tmp;
      if (i == 0  && j == n)continue;
      edge[i].pb((Edge){j,dist(in[i]-in[j]),tmp});
    }
  }

  
  /*
  rep(i,n){
    rep(j,n){
      int lim=j;
      if (abs(i-j)<=1||(j+1)%n==i%n||(i+1)%n==j%n)continue;
      if (j < i)lim+=n;
      bool isok=true;
      for(int k=i+1;k<lim;k++){
	if (ccw(in[j]-in[i],in[k]-in[i])==1){
	  //isok=false;
    	  break;
    	}
      }
//       rep(k,n){
// 	if (i<=k && k<=lim)continue;
// 	if (ccw(in[j]-in[i],in[k]-in[i])==-1){isok=false;break;}
//       }
      rep(k,n){
	if (i<=k && k<=lim)continue;
	if (k==i||k==j||k+1==i||k+1==j)continue;
	if (is_intersected_ls(in[i],in[j],in[k],in[k+1]))
	  {isok=false;break;}
      }
//       for(int k=i+1;k < lim;k++){
//  	if (is_intersected_ls(in[i],in[j],in[k],in[k+1])){isok=false;break;}
//       }
      if (!isok)continue;
      int tmp = polygon_area(in+i,j<i?lim-i+1:j-i+1);
      if (tmp > 0)continue;
      tmp=-tmp;
      edge[i].pb((Edge){j,dist(in[i]-in[j]),tmp});
    }
  }
  */

  
//   rep(i,n){
//     rep(j,edge[i].size())cout << i<<" " <<edge[i][j].num << " " <<
//       edge[i][j].dist<<" " << edge[i][j].val << endl;
//   }
  
  rep(i,n+1){
    rep(j,M)dp[i][j]=1e20;
    dp[i][0]=0;
  }
  

  rep(i,n){
    rep(j,M){
      if (i)dp[i][j]=min(dp[i][j],dp[i-1][j]);
      rep(k,edge[i].size()){
	int nexi=edge[i][k].num;
	int nexj=j+edge[i][k].val;
	double nev=dp[i][j]+edge[i][k].dist;
	if (nexj >= M)continue;
	dp[nexi][nexj]=min(dp[nexi][nexj],nev);
      }
    }
  }
  
//   rep(i,n){
//        rep(j,M){
//          if (dp[i][j] < 1e10)cout << i<<" " << j << " " << dp[i][j]<<endl;
//        }
//   }
  
  int ans = 0;
  for(int j=M-1;j>0;j--){
    rep(i,n+1){
      if (dp[i][j] <= r+eps){return j;}
    }
  }
  return 0;
}

main(){
  int n,r;
  int tc=1;
  P tmp[N],hoge[N],in[N],out[N];
  while(cin>>n>>r && n){
    int p=0;
    int ans=0;
    rep(i,N)edge[i].clear();
    
    rep(i,n){
      int x,y;
      cin>>x>>y;
      tmp[i]=P(x,y);
      hoge[i]=tmp[i];
    }
    ans = polygon_area(hoge,n);
    ConvexHull(n,hoge,out,p);
    int lim=polygon_area(out,p);
    
    int move=-1;
    rep(i,n){
      if (out[0] == tmp[i]){
	move=i;
	break;
      }
    }
    rep(i,n){
      in[i]=tmp[(i+move)%n];
    }
    tmp[n]=tmp[0];
    in[n]=in[0];
    rep(i,n)in[n+i]=in[i];
    rep(i,n)tmp[n+i]=tmp[i];
//     cout << "[";
//     rep(i,n){
//       //    cout << i <<" " << in[i]<<endl;
//       cout <<in[i]-P(30,50) <<",";
//     }
//     cout << in[0]-P(30,50) <<"]," << endl;
    
//    cout << ans << endl;
    ans+=solve(n,in,(double)r,lim-ans);
    //ans+=solve(n,tmp,(double)r,lim-ans);
    //    if (ans > lim)cout <<"error"<<endl;//assert(false);
    printf("case %d: %.1lf\n",tc++,ans/2.);
  }
}

/*
18.9737 234
73.5459 528
42.9535 158
*/
accuracy: 1
time_ms: 630
memory_kb: 10000
final_rank: 4