山东省第一节省赛 C (计算几何+dp)

主要说一下状态表示。

这里的状态是以d(i,j)代表以i开始,以j结尾的向量往下走还需要至少删几个点,那么最终答案就是对每个状态求一下最优值。

计算几何部分应该用叉积和点积来考虑。可以发现顺时针和逆时针成立的条件正好相反。

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int inf = 10000;
const int N = 310;
struct point{
  int x,y;
  point(int x=0,int y=0):x(x),y(y){}
}a[N];
int cross(point A,point b){
  return A.x*b.y-A.y*b.x;
}
int Dot(point A,point b){
  return A.x*b.x+A.y*b.y;
}
int judge(int i,int j,int k){
  point A(a[j].x-a[i].x,a[j].y-a[i].y);
  point B(a[k].x-a[j].x,a[k].y-a[j].y);
  int cro = cross(A,B),dot = Dot(A,B);
  if(cro==0){
     return dot > 0;
  }
  else if(cro>0) return 1;
  return 0;
}
int d[N][N];
int n;
void init(){}
int dp(){
  int res=inf;
  for(int j=n;j>=2;j--)
    for(int i=1;i<j;i++){
      if(j==n) d[i][j]=0;
      else{
        d[i][j]=n-j;
        for(int k=j+1;k<=n;k++){
           if(judge(i,j,k))
            d[i][j]=min(d[i][j],d[j][k]+k-j-1);
        }
      }
      res=min(res,d[i][j]+(j-i-1)+i-1);
   }
  return res;
}
int dp2(){
  int res=inf;
  for(int j=n;j>=2;j--)
    for(int i=1;i<j;i++){
      if(j==n) d[i][j]=0;
      else{
        d[i][j]=n-j;
        for(int k=j+1;k<=n;k++){
           if(!judge(i,j,k))
            d[i][j]=min(d[i][j],d[j][k]+k-j-1);
        }
      }
      res=min(res,d[i][j]+(j-i-1)+i-1);
  }
  return res;
}
int main()
{
    while(scanf("%d",&n)==1 && n){
       for(int i=n;i>=1;i--)
        scanf("%d %d",&a[i].x,&a[i].y);
       init();
       int ans1 = dp();
       init();
       int ans2 = dp2();
       if(!ans1) printf("C\n");
       else if(!ans2) printf("CC\n");
       else if(ans1<=ans2)
           printf("Remove %d bead(s), C\n",ans1);
       else printf("Remove %d bead(s), CC\n",ans2);
       printf("\n");
    }
    return 0;
}



你可能感兴趣的:(山东省第一节省赛 C (计算几何+dp))