题面:

传送门: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)的更多相关文章

  1. 洛谷P2831 愤怒的小鸟(状压dp)

    题意 题目链接 Sol 这题....我样例没过就A了??..算了,就当是样例卡精度吧.. 直接状压dp一下,\(f[sta]\)表示干掉\(sta\)这个集合里面的鸟的最小操作数 转移的时候判断一下一 ...

  2. 【题解】P2831 愤怒的小鸟 - 状压dp

    P2831愤怒的小鸟 题目描述 \(Kiana\) 最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于 \((0,0)\) 处,每次 \(Kiana\) 可以 ...

  3. Luogu P2831 愤怒的小鸟(状压+记忆化搜索)

    P2831 愤怒的小鸟 题意 题目描述 Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于\((0,0)\)处,每次Kiana可以用它向第一象限发射 ...

  4. P2831 愤怒的小鸟 状压dp

    这个题主要是预处理比较复杂,先枚举打每只鸟用的抛物线,然后找是否有一个抛物线经过两只鸟,然后就没了. 题干: 题目描述 Kiana 最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上 ...

  5. NOIP2016愤怒的小鸟 [状压dp]

    愤怒的小鸟 题目描述 Kiana 最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于 (0,0) 处,每次 Kiana 可以用它向第一象限发射一只红色的小鸟, ...

  6. [Luogu P3959] 宝藏 (状压DP+枚举子集)

    题面 传送门:https://www.luogu.org/problemnew/show/P3959 Solution 这道题的是一道很巧妙的状压DP题. 首先,看到数据范围,应该状压DP没错了. 根 ...

  7. luogu2831 [NOIp2016]愤怒的小鸟 (状压dp)

    由范围可以想到状压dp 两个点(再加上原点)是可以确定一个抛物线的,除非它们解出来a>=0,在本题中是不合法的 这样的话,我们可以预处理出由任意两个点确定的抛物线所经过的所有的点(要特别规定一下 ...

  8. [noip2016]愤怒的小鸟<状压dp+暴搜>

    题目链接:https://vijos.org/p/2008 现在回过头去看去年的考试题,发现都不是太难,至少每道题都有头绪了... 这道题的数据范围是18,这么小,直接暴力呗,跑个暴搜就完了,时间也就 ...

  9. NOIP2016Day2T3愤怒的小鸟(状压dp) O(2^n*n^2)再优化

    看这范围都知道是状压吧... 题目大意就不说了嘿嘿嘿 网上流传的写法复杂度大都是O(2^n*n^2),这个复杂度虽然官方数据可以过,但是在洛谷上会TLE[百度搜出来前几个博客的代码交上去都TLE了], ...

随机推荐

  1. Leetcode PHP题解--D125 107. Binary Tree Level Order Traversal II

    val = $value; } * } */ class Solution { private $vals = []; /** * @param TreeNode $root * @return In ...

  2. NMOS和PMOS区别

    在很多电路途中会出现NMOS和PMOS管,因为不是中文那么直接,都说管压降之类的,但其实它的导通很重要以及区别,关系到你点亮电子元件> 参考: 1.https://blog.csdn.net/l ...

  3. 安装、验证安装 Oracle Database XE 11gR2

    操作系统:Windows 10 x64 第一节:下载 Oracle Database XE 11gR2 第二节:安装.验证安装 Oracle Database XE 11gR2 第三节:Oracle ...

  4. JVM初步入门(很初级,建议只做大致了解用)

    jvm初步入门 本博客中的所有内容都是来自b站狂神说视频教程,如有侵权联系我删除. 下面是视频链接:b站狂神说 关于jvm的几个小问题 1. jvm的位置: jvm是一个运行在操作系统上的用c语言编写 ...

  5. linxu 命令

    top | grep java 统计 java 进程使用的资源比率 nohub java -jar test.war & 后台运行 test.war 程序,标准输出到 test.war 程序目 ...

  6. xxe 新手学习记录

    在做某题时遇到了xxe漏洞,学习+记录 这里因为环境暂时关了,现在复现不了,所以在网络上又找到了一些xxe题目环境 这里有 PikaChu靶场里的xxe环境,这个环境可以在BUUCTF里开,但是这里我 ...

  7. JavaScript常用对象介绍

    目录 对象(object) 对象的创建方式 点语法 括号表示法 内置对象 Array 数组创建方式 检测数组 转换方法 分割字符串 栈方法 队列方法 重排序方法 操作方法 位置方法 迭代方法 Stri ...

  8. activiti 流程部署 保存流程图到数据库 保存二进制图片 存储失败

    activiti 流程部署 保存流程图到数据库  保存二进制图片 存储失败 具体错误如下 具体 junit测试 结果 :提示如下: 解决方法: 数据库版本不同 无法保存二进制文件到数据库表中!5.5. ...

  9. web中的HTML CSS

    HTML  超文本标记语言      页面的结构  首行声明文档类型>根标记>头部标记/主体标记      标记         div 布局 切割 分割 划分区域         spa ...

  10. k8s集群调度方案

    Scheduler是k8s集群的调度器,主要的任务是把定义好的pod分配到集群节点上 有以下特征: 1  公平   保证每一个节点都能被合理分配资源或者能被分配资源 2  资源高效利用   集群所有资 ...