洛谷 P2831 愤怒的小鸟

洛谷:P2831 愤怒的小鸟

题目传送门

本题是一道很明显的状压DP,麻烦的是浮点数的处理和抛物线的计算,这里讲一些注意事项:

一.浮点数判相等:

 

二.抛物线的判断:

题目中的抛物线有两个未知数,在正常情况下,每两点便可确定一条抛物线,但以下情况除外:

1.两点所在的直线经过原点

2.两点横坐标相等

3.a < 0

做法:

1、N3预处理出所有抛物线,及其能经过的点。

2、转移。

其中还有许多优化,这里我用的是最暴力的方法。

注:本题可用随机化。

#include<cstdio>
#include<algorithm>
#include<cstring>
int para[650];
int tot;
#define inf 1000001
int min(int x,int y)
{
  return x<y?x:y;
}
double Mx(double x,double y)
{
  return x>y?x:y;
}
double abs(double x)
{
  return x>0?x:-x;
}
int dp[1<<19];
double X[21],Y[21];
#define eps 1e-9
bool Be(double x,double y)
{
  if(abs(x-y)<=eps*Mx(abs(x),abs(y)))
  return true;
  else
  return false;
   
}int wuxian[600],jzw=0;
void init()
{
  for(int i=0;i<=18;i++) X[i]=Y[i]=0;
  for(int i=0;i<=(1<<19)-1;i++)
      dp[i]=inf;
      dp[0]=0;
        jzw=tot=0;
  for(int i=1;i<=400;i++)para[i] = 0;
}
double geta(double x1,double y1,double x2,double y2)
{
  return (y1*x2-y2*x1)/(x1*x1*x2-x2*x2*x1);
}
double getb(double x1,double y1,double x2,double y2)
{
  return (y1*x2*x2-y2*x1*x1)/(x1*x2*x2-x2*x1*x1);
}
double getk(double x1,double y1,double x2,double y2)
{
  if(Be(x1,x2)) return inf;
  return (y1-y2)/(x1-x2);
}
bool delta(double x1,double y1,double x2,double y2)
{
  if(x1==x2) return 0 ;
  double k=getk(x1,y1,x2,y2);
  double b=y1-k*x1;
  if(Be(b,0))
      return 1;
  if(Be(b,eps))
      return 1;
  return 0;
}
void build_dp(int n)
{
  for(int i=0;i<n;i++)
  {
      double x1 = X[i+1];
      double y1 = Y[i+1];
      dp[1<<i] = 1;
    //   printf("%f %f",x1,y1);
      for(int j=0;j<n;j++)
      {
          double x2 = X[j+1];
          double y2 = Y[j+1];
          if(x1==x2) continue;
           
          double a = geta(x1,y1,x2,y2);
          double b = getb(x1,y1,x2,y2);
      //     printf("%f ",a);
          if(a>0 || delta(x1,y1,x2,y2)) continue ;
          dp[(1<<j)|(1<<i)] = 1;
          int sta=(1<<j)|(1<<i);
          for(int k=0;k<n;k++)
          {
              double x3 = X[k+1];
              double y3 = Y[k+1];
              dp[1<<k] = 1;
              double yy = a*x3*x3+b*x3;
              if(Be(yy,y3))
              {
                  sta|=1<<k;
                  dp[sta]=1;
              }
          }
      }
  }
}

void build_para(int n)
{
  for(int i=1;i<=(1<<n)-1;i++)
  {
      if(dp[i]==1) para[++tot] = i;
  }
}
int main()
{
  int T;
  scanf("%d",&T);
  while(T--)
  {
      int n,m;
      scanf("%d%d",&n,&m);
      init();
      for(int i=1;i<=n;i++)
          scanf("%lf%lf",&X[i],&Y[i]);
      build_dp(n);
      build_para(n);
// for(int i=1;i<=tot;i++) printf("%d ",para[i]);
// for(int i=1;i<=tot;i++) printf("%d ",para[i]);  
      for(int i=1;i<=tot;i++)
      {
          int hit = para[i];
          for(int j=0;j<=(1<<n)-1;j++)
          dp[j|hit] = min(dp[j|hit],dp[j]+1);
      }
      printf("%d ",dp[(1<<(n))-1]);
  }
}



原文地址:https://www.cnblogs.com/Marcelo/p/13806108.html