愤怒的小鸟

来源:互联网 发布:电脑屏幕录制软件直播 编辑:程序博客网 时间:2024/04/29 18:51

QAQ
状压DP
1表示小鸟打掉了,0表示没打掉。
dp[s]表示到S状态最少需要几步。


怎么枚举a,b。
因为c=0,只需两只猪即可确定一条曲线。
boom[i][j]表示i猪和j猪确定的曲线可以打掉的猪。


关于转移
枚举状态s中第一只没有打掉的小猪,固定i,枚举j即可


注意初始化


#include <cstdio>#include <iostream>#include <cstring>#define ll long longusing namespace std;const int maxm=(1<<19)+100; const double limit=1e-7;int boom[20][20];double x[20],y[20];int dp[maxm];void init(){    memset(dp,127/3,sizeof(dp));    memset(x,0,sizeof(x));    memset(y,0,sizeof(y));    memset(boom,0,sizeof(boom));}double fabs(double a){    if(a<0) return -a;    return a;}void work(){    init();    int n,m;    scanf("%d%d",&n,&m);    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++)         {            boom[i][j]=0;            //boom[i][j]=(boom[i][j]|(1<<(i-1)));            //boom[i][j]=(boom[i][j]|(1<<(j-1)));            double f=x[i]*x[j]*(x[i]-x[j]);              double a=x[j]*y[i]-x[i]*y[j];              double b=x[i]*x[i]*y[j]-x[j]*x[j]*y[i];              if(a*f<0)//开口向下            {             for(int k=1;k<=n;k++)             if(fabs(a*x[k]*x[k]+b*x[k]-f*y[k])<limit) boom[i][j]|=1<<(k-1);            }            //boom[i][j]=~boom[i][j];            //boom[j][i]=boom[i][j];         }    }    dp[0]=0;     for(int i=0;i<=(1<<n)-1;i++)    {     int w=1;     while ((i>>(w-1))&1&&w<=n) w++;     dp[i|(1<<(w-1))]=min(dp[i]+1,dp[i|(1<<w-1)]);      for(int j=w+1;j<=n;j++)      if(i|boom[w][j]<=(1<<n)-1)       dp[i|boom[w][j]]=min(dp[i|boom[w][j]],dp[i]+1);    }    printf("%d\n",dp[(1<<n)-1]);   }int main(){    int t;    scanf("%d",&t);    while(t--)     work();}
原创粉丝点击