P2831 愤怒的小鸟

P2831 愤怒的小鸟

思路

一看到所有数范围这么小,就是一个赤裸裸的状态压缩DP了
d p [ S ] dp[S] dp[S]表示当前死了的猪集合为S时,至少用了多少只鸟
显然有以下方程
d p [ 0 ] = 0 dp[0]=0 dp[0]=0
需要单独一只鸟打死这只猪时:
d p [ S ∣ ( 1 < < ( i − 1 ) ) ] = m i n ( d p [ S ∣ ( 1 < < ( i − 1 ) ) ] , d p [ S ] + 1 ) dp[S|(1<<(i-1))]=min(dp[S|(1<<(i-1))],dp[S]+1) dp[S(1<<(i1))]=min(dp[S(1<<(i1))],dp[S]+1)
需要打死的猪在一条抛物线上时:
d p [ S ∣ l i n e [ i ] [ j ] ] = m i n ( d p [ i ∣ l i n e [ i ] [ j ] ] , d p [ S ] + 1 ) dp[S|line[i][j]]=min(dp[i|line[i][j]],dp[S]+1) dp[Sline[i][j]]=min(dp[iline[i][j]],dp[S]+1
但是!这个算法的时间复杂度是 O ( T n 2 2 n ) O(Tn^22^n) O(Tn22n)
于是我们考虑优化:
x x x为满足 S & ( 1 < < ( x − 1 ) ) = 0 S\&(1<<(x-1))=0 S&(1<<(x1))=0的最小正整数,即 x x x这个点当前不属于集合 S S S,则由 S S S扩展的所有线都要经过 x x x转移(因为这只猪必须要打),因为经过 x x x的所有线数量为 n n n,所以我们只要预处理处所有的 x x x即可降低一个 n n n的复杂度。

思路来源(感谢大佬)
取自dalao题解
dalao原话orz
细节:

  1. 在解方程时,考虑把 a , b a,b a,b当做未知量, x 2 , x , y x^2,x,y x2,x,y当做已知进行处理
  2. 注意精度
#include <bits/stdc++.h>
using namespace std;
const double eps=1e-8;
int t,dp[1<<20],line[20][20],n,m,lownbit[1<<20];
double x[20],y[20];
void epa(double &x,double &y,double a1,double b1,double c1,double a2,double b2,double c2){
	y=(c2*a1-c1*a2)/(b2*a1-b1*a2);
	x=(c1-b1*y)/a1;
}
int main(){
	for(int i=0;i<(1<<18);i++){
		int j=1;
		for(;j<=18&&i&(1<<(j-1));j++);
		lownbit[i]=j;
	}
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		memset(line,0,sizeof(line));memset(dp,0x3f,sizeof(dp));dp[0]=0;
		for(int i=1;i<=n;i++){
			scanf("%lf%lf",&x[i],&y[i]);
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				if(fabs(x[i]-x[j])<eps)	continue;
				double a,b;
				epa(a,b,x[i]*x[i],x[i],y[i],x[j]*x[j],x[j],y[j]);
				if(a>-eps)	continue;
				for(int k=1;k<=n;k++){
					if(fabs(a*x[k]*x[k]+b*x[k]-y[k])<eps){
						line[i][j]|=(1<<(k-1));
					}
				}
			}
		}
		for(int i=0;i<(1<<n);i++){
			int j=lownbit[i];
			dp[i|(1<<(j-1))]=min(dp[i|(1<<(j-1))],dp[i]+1);
			for(int k=1;k<=n;k++){
				dp[i|line[j][k]]=min(dp[i|line[j][k]],dp[i]+1);
			}
		}
		printf("%d\n",dp[(1<<n)-1]);
	}
	return 0;
}

总结:对于这道题,首先从数据范围入手猜测是状态压缩,然后考虑设计转移方程,对于题目条件中的抛物线,看看这只猪是和其他抛物线一起打还是单独进行转移,接着考虑如何降低时间复杂度,从需要被打掉的的猪的类型入手分析,考虑怎么去掉无用状态, b i n g o ! bingo! bingo

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值