noip 2016(憤怒的小鳥)(狀壓dp)
阿新 • • 發佈:2019-02-17
狀壓dp,每位代表一隻豬,1為豬打到了,0為豬還沒打到
兩個豬的座標確定一條拋弧線(即為打出鳥的軌跡)
g[i][j]表示由i豬和j豬確定的拋弧線,能打到的豬。(是一個二進位制的狀態)
預處理:把能被i豬和j豬確定的這條拋弧線能打到的豬都用狀壓的1來表示,存到g[i][j]裡。
dp[s]表是當狀態為s時所需要的最少拋弧線 (最少小鳥);
當發射軌跡為i豬和j豬確定的拋弧線的小鳥時 dp[s|g[i][j]]>dp[s]+1, dp[s|g[i][j]]=dp[s]+1;
求需要最少的拋物線數量(最少小鳥),把dp賦初值為很大的數
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; int g[20][20],dp[1<<20],n,m; double x23[20],y23[20]; void yuchuli(int zhu1,int zhu2,double x1f,double x1,double y1,double x2f,double x2,double y2) { double x=x1f/x1*x2; double xx=x1/x1*x2; double y=y1/x1*x2; double a=(y-y2)/(x-x2f); x=x1f/x1f*x2f; xx=x1/x1f*x2f; y=y1/x1f*x2f; double b=(y-y2)/(xx-x2); if(a>=0) return ;//a>=0沒有任何豬能打掉,不合法 for(int i=1;i<=n;i++) if(abs(a*x23[i]*x23[i]+b*x23[i]-y23[i])<=1e-6)//abs是必要的負數可以負很多 g[zhu1][zhu2]|=(1<<(i-1)) ; } int main() { //freopen("angrybirds.in","r",stdin); // freopen("angrybirds.out","w",stdout); int t; cin>>t; for(int z=1;z<=t;z++) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lf%lf",&x23[i],&y23[i]); memset(dp,127,sizeof(dp)); memset(g,0,sizeof(g)); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(i!=j)yuchuli(i,j,x23[i]*x23[i],x23[i],y23[i],x23[j]*x23[j],x23[j],y23[j]); //拋物線,兩個點確定一條拋物線 } for(int i=1;i<=n;i++) g[i][i]=(1<<(i-1)); dp[0]=0; for(int s=0;s<=(1<<n)-1;s++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(dp[s|g[i][j]]>1+dp[s]) dp[s|g[i][j]]=1+dp[s]; printf("%d\n",dp[(1<<n)-1]); } return 0; }