NOIP2016愤怒的小鸟

设dp[S]表示已经打了的猪的的序号组成的集合,那么我们枚举一个i表示这一次要打个猪,然后再枚举一个j,表示这一次把i和j一起打掉,那么预处理一个bit数组使得bit[i][j]表示以i和j的坐标确定的抛物线可以打掉的所有的猪,那么就由dp[S]+1转移到了dp[S|bit[i][j]]了,最后的答案就是dp[2^n-1].

#include <bits/stdc++.h> 
#define N 20  
#define eps 1e-8 
#define INF 0x3f3f3f3f
using namespace std;
int T,n,m;   
int g[N][N],f[1<<20]; //g存选择猪i j f存状压结果  
double x[N],y[N],a,b; //前向星存猪 
bool same(double a,double b) { return fabs(a-b)<=eps; } //精度判重   
int mymin(int a,int b) { return a<b?a:b; }
void Clear() //初始化 
{
    for(int i=1;i<=n;i++) 
      for(int j=1;j<=n;j++) 
        g[i][j]=0;    
    int k=1<<n; 
    for(int i=1;i<k;i++) 
      f[i]=INF; 
}
int main()
{
  scanf("%d",&T); 
  while(T--) 
  {
    scanf("%d%d",&n,&m);  
      Clear();        
      for(int i=1;i<=n;i++)  scanf("%lf%lf",&x[i],&y[i]); 
      for(int i=1;i<n;i++)
      for(int j=i+1;j<=n;j++) 
      {
          if(same(x[i],x[j])) continue; //如果横坐标相同一定打不了   
          a=(y[i]/x[i]-y[j]/x[j])/(x[i]-x[j]); 
          if(a>=0) continue; 
          b=y[i]/x[i]-a*x[i]; 
          for(int k=1;k<=n;k++)  //所有符合的都加进去  
            if(same(a*x[k]+b,y[k]/x[k])) 
              g[i][j]|=(1<<(k-1)); //01000101 表示能打1 3 7 这三只猪   
      } 
    f[0]=0; //边界条件 一只都不打   
    int k=1<<n; 
    for(int i=0;i<k;i++)   //每一种状态  
      for(int j=1;j<=n;j++) // 每一只猪  
        if(!(i & (1<<(j-1))))   // 能增加打掉的猪 i的状态那个位置是0  
        {
            for(int k=j;k<=n;k++) //前面的都打过了 
            { 
              //特判   从直接打掉和加一条中选取最小值
              if(k==j)
              {
                  f[i|(1<<(j-1))]=mymin(f[i|(1<<(j-1))],f[i]+1); 
                  continue; 
               }  
              if(same(x[k],x[j])) continue; //横坐标相同直接过不存在 
              f[i|g[j][k]]=mymin(f[i|g[j][k]],f[i]+1);  //选取该条抛物线 或者加一条  
            } 
            break; 
        } 
    printf("%d\n",f[(1<<n)-1]);  
  } 
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值