[Luogu P2831] 愤怒的小鸟 (状压DP)
题面:
传送门:https://www.luogu.org/problemnew/show/P2831
Solution
首先,我们可以先康一康题目的数据范围:n<=18,应该是状压或者是搜索。
事实上,这题搜索和状压DP都是能做的。
(因为搜索在我心中留下了阴影(斗地主),所以在这里,我讲状压DP的做法)
根据我们以往设计状压DP的经验,我们可以很轻松地设计这一题的状态:
设f[i]表示打下的猪猪的状态为i的方案数,(状态在这里用二进制方式来表示,例如:00101表示打下了第1和第3只猪)
那么有: f[i] = min(f[j])+1 (j为i的子集)
这里用到一个枚举子集的技巧,对于一个状态i,它可以这样枚举子集:
for(int j=i;j>=0;j=(j-1)&i) (至于证明,你可以在草稿纸上画画,很快就会发现它的精妙了)
那我们怎么判断能否从状态 j 转移到 i 呢?
首先,根据数学常识,我们需要3个x不一样的点才能确定一条抛物线。这题已经固定了原点了,所以我们还需要两个点来确定一条抛物线。
如果j与i只有一个或两个x不同的点 是不同的,那显然是可以转移的。
对于有两个以上的点,我们可以用前两个点通过解二元一次方程来计算函数的a与b,然后再去一个一个判断每个不同的点是否在这条抛物线上。
对于如何解二元一次方程..........(这应该是数学常识吧)
复杂度O (3^n*n*T)
显然TLE,事实上,这样做只能得60分。
那怎么优化复杂度呢?
刚刚的枚举子集显然是不可行了,那我们可以换个思路。
我们可以枚举点。
对于某一种状态,我们肯定可以枚举两个(或一个)没有用过的点去构成新的抛物线从而更新其他的状态。
这样子,我们成功地把复杂度降为了 O(2^n*n^2*T)
依然过不了,事实上,这样做能得85分。
上一个作法已经和正解很接近了。
我们可以考虑这样优化方程:

这样子,我们复杂度就降为了O(2^n*n*T)
就酱,我们就可以把这道题切掉啦(´▽`)ノ
Code
//Luogu P2831 愤怒的小鸟
//Sep,19th,2018
//状压DP
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int N=18+2;
const double eps=1e-7;
struct node
{
double x,y;
}nd[N];
long long f[1<<N];
int n,POW[N],g[N][N];
inline double pf(double x)
{
return x*x;
}
bool solve(node A,node B,double &a,double &b)
{
if(fabs(A.x-B.x)<=eps) return false;
a=(B.x*A.y-A.x*B.y)/(pf(A.x)*B.x-pf(B.x)*A.x);
b=(pf(B.x)*A.y-pf(A.x)*B.y)/(pf(B.x)*A.x-pf(A.x)*B.x);
if(a>=0) return false;
return true;
}
double fun(double x,double a,double b)
{
return a*pf(x)+b*x;
}
int main()
{
POW[0]=1;
for(int i=1;i<N;i++)
POW[i]=POW[i-1]*2;
int T,tt;
scanf("%d",&T);
for(;T>0;T--)
{
memset(g,0,sizeof g);
scanf("%d%d",&n,&tt);
for(int i=1;i<=n;i++)
scanf("%lf%lf",&nd[i].x,&nd[i].y); for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
double a=0,b=0;
bool OK=solve(nd[i],nd[j],a,b);
if(OK==false) continue;
for(int k=1;k<=n;k++)
if(fabs(fun(nd[k].x,a,b)-nd[k].y)<=eps)
g[i][j]+=POW[k-1];
} memset(f,0x3f,sizeof f);
f[0]=0;
int to=(1<<n)-1,used[N];
for(int i=0;i<to;i++)
{
memset(used,0,sizeof used);
int temp=i,j;
for(j=n-1;j>=0;j--)
if(temp-POW[j]>=0)
{
temp-=POW[j];
used[j+1]=true;
}
for(j=1;j<=n;j++)
if(used[j]==false)
break;
f[i|POW[j-1]]=min(f[i|POW[j-1]],f[i]+1);
for(int k=j+1;k<=n;k++)
if(used[k]==false and g[j][k]!=0)
f[i|g[j][k]]=min(f[i|g[j][k]],f[i]+1);
} printf("%lld\n",f[to]);
}
return 0;
}
[Luogu P2831] 愤怒的小鸟 (状压DP)的更多相关文章
- 洛谷P2831 愤怒的小鸟(状压dp)
题意 题目链接 Sol 这题....我样例没过就A了??..算了,就当是样例卡精度吧.. 直接状压dp一下,\(f[sta]\)表示干掉\(sta\)这个集合里面的鸟的最小操作数 转移的时候判断一下一 ...
- 【题解】P2831 愤怒的小鸟 - 状压dp
P2831愤怒的小鸟 题目描述 \(Kiana\) 最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于 \((0,0)\) 处,每次 \(Kiana\) 可以 ...
- Luogu P2831 愤怒的小鸟(状压+记忆化搜索)
P2831 愤怒的小鸟 题意 题目描述 Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于\((0,0)\)处,每次Kiana可以用它向第一象限发射 ...
- P2831 愤怒的小鸟 状压dp
这个题主要是预处理比较复杂,先枚举打每只鸟用的抛物线,然后找是否有一个抛物线经过两只鸟,然后就没了. 题干: 题目描述 Kiana 最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上 ...
- NOIP2016愤怒的小鸟 [状压dp]
愤怒的小鸟 题目描述 Kiana 最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于 (0,0) 处,每次 Kiana 可以用它向第一象限发射一只红色的小鸟, ...
- [Luogu P3959] 宝藏 (状压DP+枚举子集)
题面 传送门:https://www.luogu.org/problemnew/show/P3959 Solution 这道题的是一道很巧妙的状压DP题. 首先,看到数据范围,应该状压DP没错了. 根 ...
- luogu2831 [NOIp2016]愤怒的小鸟 (状压dp)
由范围可以想到状压dp 两个点(再加上原点)是可以确定一个抛物线的,除非它们解出来a>=0,在本题中是不合法的 这样的话,我们可以预处理出由任意两个点确定的抛物线所经过的所有的点(要特别规定一下 ...
- [noip2016]愤怒的小鸟<状压dp+暴搜>
题目链接:https://vijos.org/p/2008 现在回过头去看去年的考试题,发现都不是太难,至少每道题都有头绪了... 这道题的数据范围是18,这么小,直接暴力呗,跑个暴搜就完了,时间也就 ...
- NOIP2016Day2T3愤怒的小鸟(状压dp) O(2^n*n^2)再优化
看这范围都知道是状压吧... 题目大意就不说了嘿嘿嘿 网上流传的写法复杂度大都是O(2^n*n^2),这个复杂度虽然官方数据可以过,但是在洛谷上会TLE[百度搜出来前几个博客的代码交上去都TLE了], ...
随机推荐
- django_apscheduler 0.4.0删除了name字段
使用django_apscheduler时默认使用了最新版本,为0.4.2版本,但是在这个版本中,使用migrate 生成定时任务模型时没有了name字段,导致之前写的定时任务不能执行. 翻了下 dj ...
- 怎样优雅的实现INotifyPropertyChanged
第一 安装nuget包 PropertyChanged.Fody. 第二 在类的上方加上 [PropertyChanged.AddINotifyPropertyChangedInterface] 类似 ...
- AD技巧之原理图元器件统一重新编号
本文将简要介绍Altium Designer中如何进行原理图元器件统一命名,这是Altium Designer软件一个小技巧,在学习和工程实践中,都十分有用的技能. 第一步:打开原理图 第二步:点击& ...
- JVM内存布局(又叫Java运行时数据区)
JVM 堆中的数据是共享的,是占用内存最大的一块区域. 可以执行字节码的模块叫作执行引擎. 执行引擎在线程切换时怎么恢复?依靠的就是程序计数器. JVM 的内存划分与多线程是息息相关的.像我们程序中运 ...
- RHSA-2017:1842-重要: 内核 安全和BUG修复更新(需要重启、存在EXP、本地提权、代码执行)
[root@localhost ~]# cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) 修复命令: 使用root账号登陆She ...
- Python库之SQLAlchemy
一.SQLAlchemy简介 1.1.SQLAlchemy是什么? sqlalchemy是一个python语言实现的的针对关系型数据库的orm库.可用于连接大多数常见的数据库,比如Postges.My ...
- 关于android和Linux的一些问题
1.Android为什么选择java? 由于java虚拟机,实现软件层的编程与硬件无关性(无需进行特定编译或平台配置). 2.Android和Linux内核区别? Android上的应用软件运行在da ...
- linux系统上用户态pppoe收发包过程
花了几天看了一下ppp/pppoe有关的东西,画了一下用户态pppoe收发包的示意图.
- spring boot:用itextpdf处理pdf表格文件(spring boot 2.3.2)
一,什么是itextpdf? 1,itextpdf的用途 itextpdf是用来生成PDF文档的一个java类库, 通过iText可以生成PDF文档, 还可以把XML/Html文件转化为PDF文件 2 ...
- CentOS 8 安装 oniguruma 和 oniguruma-devel
一,oniguruma是什么? oniguruma是一个处理正则表达式的库,我们之所以需要安装它, 是因为在安装php7.4的过程中,mbstring的正则表达式处理功能对这个包有依赖性, 所以我们要 ...