码迷,mamicode.com
首页 > 其他好文 > 详细

状压DP之愤怒的小鸟

时间:2020-06-26 18:13:52      阅读:50      评论:0      收藏:0      [点我收藏+]

标签:bit   数学   代码   浮点   接下来   mem   十分   两种   差值   

题目

传送们P2831
题目较长,不加以赘述

直接步入正题

首先是数学知识,我们可以先根据给出的任意两只猪构建相应的抛物线,同时再构建完之后应判断抛物线的合法性(比如a小于0啊,等等),公式推演就不在这里说了,这里需要注意的是对于浮点型判断,不能单纯用相等,这里我们可以定义一个十分小的数,将两数差值与其相比,一般用到数为\(1e-6\)就可了,根据两个两只猪得来的抛物线,将其他猪带入,求相应抛物线所能经过的所有猪的状态,与原状态求或,即\(num[i][j]|=(1<<(k-1))\),就是\(k\)\(i\)\(j\)所在抛物线上时更新该抛物线状态;
处理完这个,我们可以来定义DP数组了,对于这道题,我们只需要一维数组就可了,定义\(F[i]\)数组代表打死\(i\)状态下猪的所需最少小鸟数,首先枚举状态,其次枚举两层猪的个数(用于枚举抛物线),为了避免重复,第二遍枚举我们从第一遍所在位置开始枚举,在这里我们可以稍稍进行一下优化,在进行第一遍枚举时,如果这只猪已经包含在当前状态内,我们可以直接跳过,因为当我们跳过后,第二遍枚举有两种情况,即第一种,第二遍枚举的猪也包含在当前状态下,这时候可以直接跳过,第二种,所枚举的猪并不在当前状态下,需要进行操作,但是第一层循环会重复操作,故在进行第一遍枚举时,如果这只猪已经包含在当前状态内,我们可以直接跳过,来进行一个优化;
然后是转移方程,分为两种情况

  1. \(i\)\(j\)相等时,那么我们有\(f[i|(1<<(j-1))]=min(f[i|(1<<(j-1))],f[i]+1)\),这种情况下\(F[i][(1<<(j-1))]\)只需要转移上一状态,或者在当前状态下多射出一直小鸟;
  2. \(i\)\(j\)不相等时,\(f[i|num[j][k]]=min(f[i|num[j][k]],f[i]+1)\),解释同上;

还有一点,

因为本道题是多组测试数据,记得初始化

接下来是代码

#include<bits/stdc++.h>
using namespace std;
int T,n,m,num[20][20],f[1000000];
double x[20],y[20];
bool same(double x,double y){return fabs(x-y)<1e-6;}//判断相等与否的函数
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)scanf("%lf%lf",&x[i],&y[i]);
		memset(num,0,sizeof(num));//num数组初始化
		for(int i=1;i<=n;i++){//第一遍枚举猪
			for(int j=i+1;j<=n;j++){//第二遍枚举猪
				if(same(x[i],x[j]))continue;//x[i]=x[j]无法构成抛物线
				double a=(y[j]/x[j]-y[i]/x[i])/(x[j]-x[i]);//公式推导
				if(a>0)continue;//a>0不合法抛物线,跳过
				double 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]))num[i][j]|=(1<<(k-1));//如果可以,更新
				}
			}
		}
		memset(f,0x3f3f3f3f,sizeof(f));//初始化f数组
		f[0]=0;//打死0这个状态下的猪需要小鸟0只
		for(int i=0;i<=(1<<n)-1;i++){//枚举状态
        	      for(int j=1;j<=n;j++){//第一层枚举猪
        		      if(!(i&(1<<(j-1)))){//优化(具体见上)
            		            for(int k=j;k<=n;k++){//第二层枚举猪
                		          if(j==k)f[i|(1<<(j-1))]=min(f[i|(1<<(j-1))],f[i]+1);//j=k的转移情况
                		          f[i|num[j][k]]=min(f[i|num[j][k]],f[i]+1);//j!=k的转移情况
               		            }
               
       		              }
       		      }
       	      }
   	      printf("%d\n",f[(1<<n)-1]);//输出打死(1<<n)-1(即所有猪)状态下猪所需要的小鸟数
	}
}

状压DP之愤怒的小鸟

标签:bit   数学   代码   浮点   接下来   mem   十分   两种   差值   

原文地址:https://www.cnblogs.com/soda-ma/p/13195260.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!