题目描述

Kiana最近沉迷于一款神奇的游戏无法自拔。

简单来说,这款游戏是在一个平面上进行的。

有一架弹弓位于(0,0)处,每次Kiana可以用它向第一象限发射一只红色的小鸟,小鸟们的飞行轨迹均为形如y=ax2+bxy=ax^2+bx的曲线,其中a,b是Kiana指定的参数,且必须满足a<0。

当小鸟落回地面(即x轴)时,它就会瞬间消失。

在游戏的某个关卡里,平面的第一象限中有n只绿色的小猪,其中第i只小猪所在的坐标为(xi,yi)。

如果某只小鸟的飞行轨迹经过了(xi,yi),那么第i只小猪就会被消灭掉,同时小鸟将会沿着原先的轨迹继续飞行;

如果一只小鸟的飞行轨迹没有经过(xi,yi),那么这只小鸟飞行的全过程就不会对第i只小猪产生任何影响。

例如,若两只小猪分别位于(1,3)和(3,3),Kiana可以选择发射一只飞行轨迹为y=−x2+4xy=-x^2+4x的小鸟,这样两只小猪就会被这只小鸟一起消灭。

而这个游戏的目的,就是通过发射小鸟消灭所有的小猪。

这款神奇游戏的每个关卡对Kiana来说都很难,所以Kiana还输入了一些神秘的指令,使得自己能更轻松地完成这个游戏。这些指令将在【输入格式】中详述。

假设这款游戏一共有T个关卡,现在Kiana想知道,对于每一个关卡,至少需要发射多少只小鸟才能消灭所有的小猪。由于她不会算,所以希望由你告诉她。

输入输出格式

输入格式:

第一行包含一个正整数T,表示游戏的关卡总数。

下面依次输入这T个关卡的信息。每个关卡第一行包含两个非负整数n,m,分别表示该关卡中的小猪数量和Kiana输入的神秘指令类型。接下来的n行中,第i行包含两个正实数(xi,yi),表示第i只小猪坐标为(xi,yi)。数据保证同一个关卡中不存在两只坐标完全相同的小猪。

如果m=0,表示Kiana输入了一个没有任何作用的指令。

如果m=1,则这个关卡将会满足:至多用⌈n3+1⌉ \lceil \frac{n}{3} + 1 \rceil只小鸟即可消灭所有小猪。

如果m=2,则这个关卡将会满足:一定存在一种最优解,其中有一只小鸟消灭了至少⌊n3⌋\left \lfloor \frac{n}{3} \right \rfloor只小猪。

保证1<=n<=18,0<=m<=2,0

输出格式:

对每个关卡依次输出一行答案。

输出的每一行包含一个正整数,表示相应的关卡中,消灭所有小猪最少需要的小鸟数量

输入输出样例

输入样例#1:
2
2 0
1.00 3.00
3.00 3.00
5 2
1.00 5.00
2.00 8.00
3.00 9.00
4.00 8.00
5.00 5.00
输出样例#1:
1
1
输入样例#2:
3
2 0
1.41 2.00
1.73 3.00
3 0
1.11 1.41
2.34 1.79
2.98 1.49
5 0
2.72 2.72
2.72 3.14
3.14 2.72
3.14 3.14
5.00 5.00
输出样例#2:
2
2
3
输入样例#3:
1
10 0
7.16 6.28
2.02 0.38
8.33 7.78
7.68 2.09
7.46 7.86
5.77 7.44
8.24 6.72
4.42 5.11
5.42 7.79
8.15 4.99
输出样例#3:
6

说明

【样例解释1】

这组数据中一共有两个关卡。

第一个关卡与【问题描述】中的情形相同,2只小猪分别位于(1.00,3.00)和 (3.00,3.00),只需发射一只飞行轨迹为y=−x2+4xy = -x^2 + 4x的小鸟即可消灭它们。

第二个关卡中有5只小猪,但经过观察我们可以发现它们的坐标都在抛物线 y=−x2+6xy = -x^2 + 6x上,故Kiana只需要发射一只小鸟即可消灭所有小猪。

数据范围

题解

0.题目大意:给出第一象限的若干点,用若干条过原点的抛物线把它们完全覆盖,求最小的抛物线条数。

1.状态压缩DP

这道题数据范围较小,我们首先会想到暴搜。任选两个小猪,确定一条抛物线,然后把所有在抛物线上的小猪都打掉。把所有情况枚举一遍,取最小值。这样暴搜的复杂度是O(2nn3T)O(2^nn^3T)。而218⋅183⋅30=458647142402^{18}·18^3·30=45864714240,时间复杂度太高。2n2^n是枚举所有情况的复杂度,已经无法优化。那我们只能从n3n^3入手。用状压dp,通过一个n3n^3的预处理,可以把复杂度降到O(2nnT)O(2^nnT)。具体方法是用一个大的二进制数s来代表当前小猪的状态,1代表小猪被干掉了,0代表小猪没被干掉。比如(13)10=(1101)2(13)_{10}=(1101)_2代表第1、3、4只小猪被干掉了。

状态设计:F[s]F[s]使当前小猪的状态是s所需的最小小鸟数

状态转移:F[s|t]=min(F[s|t],F[s]+1)F[s | t]=min( F[s | t] , F[s]+1 )

初值:全赋成n(当m=1时可赋成⌈n3+1⌉ \lceil \frac{n}{3} + 1 \rceil)

s表示已经当前干掉的小猪,t表示下一步能干掉的小猪,‘|’是按位或运算。
要注意两个细节:
1.舍弃两个点横坐标相等的情况
2.舍弃a≥0a≥0的情况(因为此时小鸟会直接冲到地上或沿直线飞出去233)

代码:

记忆化搜索版:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#define N 20
#define S (1<<N)
#define eps 1e-9
using namespace std;
double x[N];
double y[N];
int dp[N][S];
int g[N][N];//g[i][j]表示干掉i和j的同时还能干掉哪些小猪
int n,m,t,ts;
int ans;
inline bool equ(double x,double y)//防止精度误差
{return fabs(x-y)<eps;
}
void dfs(int x,int y,int z)//x表示当前搜到的小猪编号,y代表当前状态,z代表已经用的小鸟数
{if(x==n) {ans=min(ans,z);return;}if(z>ans) return;//剪枝if(z>=dp[x][y]) return;//记忆化dp[x][y]=z;if((1<<x)&y) dfs(x+1,y,z);//如果当前小猪已被干掉,直接搜下一头小猪else{bool double_kill=false;for(int i=x+1;i<n;i++) if(!((1<<i)&y)) double_kill=true,dfs(x+1,y|g[x][i],z+1);if(!double_kill) dfs(x+1,y|(1<<x),z+1);}
}
void work()
{memset(g,0,sizeof(g));scanf("%d%d",&n,&m);ts=1<<n;ans=n;for(int i=0;i<n;i++)for(int j=0;j<ts;j++)dp[i][j]=n;for(int i=0;i<n;i++) scanf("%lf%lf",&x[i],&y[i]);for(int i=0;i<n;i++)for(int j=i+1;j<n;j++) if(!equ(x[i],x[j]))//舍弃横坐标相等的情况{double b=(y[i]-y[j]*(x[i]*x[i])/(x[j]*x[j]))/(x[i]-(x[i]*x[i])/x[j]);double a=(y[i]-x[i]*b)/(x[i]*x[i]);if(a>-eps) continue;//若a>=0,直接舍弃g[i][j]=(1<<i)|(1<<j);for(int k=j+1;k<n;k++) if(equ(y[k],a*x[k]*x[k]+b*x[k])) g[i][j]|=1<<k;}dfs(0,0,0);printf("%d\n",ans);
}
int main()
{scanf("%d",&t);while(t--) work();return 0;
}

循环版:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cmath>
#define N 20
#define S 1<<N
#define eps 1e-9
using namespace std;
double x[N];
double y[N];
int g[N][N];
int mk[S];//mk表示小猪的编号
int dp[S];
int t,n,m;
inline bool equ(double x,double y)
{return fabs(x-y)<eps;
}
void init()//预处理
{memset(g,0,sizeof(g));scanf("%d%d",&n,&m);for(int i=0;i<n;i++) scanf("%lf%lf",&x[i],&y[i]);for(int i=0;i<n;i++){mk[1<<i]=i;g[i][g[i][0]=1]=1<<i;for(int j=i+1;j<n;j++) if(!equ(x[i],x[j])){int r,ok,k;double b=(y[i]-y[j]*(x[i]*x[i])/(x[j]*x[j]))/(x[i]-(x[i]*x[i])/x[j]);double a=(y[i]-x[i]*b)/(x[i]*x[i]);if(a>-eps) continue;for(r=(1<<i)|(1<<j),k=0;k<n;k++)if(equ(a*x[k]*x[k]+b*x[k],y[k])) r|=(1<<k);for(ok=0,k=1;k<=g[i][0]&&!ok;k++) ok=(g[i][k]&r)==r;//剔除重复的状态if(!ok) g[i][++g[i][0]]=r;}}
}
void solve()//dp主过程
{int ts=1<<n;//总状态数for(int i=1;i<ts;i++) dp[i]=n;//初始化for(int i=0;i<ts;i++){int l=(ts-1)^i;l=mk[l&(-l)];//lowbitfor(int j=1;j<=g[l][0];j++)dp[i|g[l][j]]=min(dp[i|g[l][j]],dp[i]+1);}printf("%d\n",dp[ts-1]);
}
int main()
{scanf("%d",&t);while(t--) {init();solve();}return 0;
}

2.玄学做法

除了状压dp之外,还有一个玄学做法。就是把坐标数组随机打乱R次,每次按照顺序把小猪依次干掉,求所有小鸟数的最小值。时间复杂度O(n3TR)O(n^3TR)。在考场上为了求稳R可以取20000左右。然而,经过丧心病狂的实验,我发现R取46就能过,而且跑的飞快233。打乱的话可以用STL的random_shuffle函数,不要忘了更新随机种子。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#define maxn 20
#define eps 1e-9
using namespace std;
struct Point{double x,y;
}p[maxn];
bool vis[maxn];
int g[maxn][maxn];
int n,m,t;
inline bool equ(double x,double y)
{return fabs(x-y)<eps;
}
void work()
{scanf("%d%d",&n,&m);int ans=n;for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y);int R=46;while(R--){int tot=0;memset(vis,false,sizeof(vis));random_shuffle(p+1,p+n+1);for(int i=1;i<=n;i++) if(!vis[i]){vis[i]=true;for(int j=i+1;j<=n;j++) if(!vis[j]){if(equ(p[i].x,p[j].x)) continue;double b=(p[i].y-p[j].y*(p[i].x*p[i].x)/(p[j].x*p[j].x))/(p[i].x-(p[i].x*p[i].x)/p[j].x);double a=(p[i].y-p[i].x*b)/(p[i].x*p[i].x);if(a>=-eps) continue;vis[j]=true;for(int k=j+1;k<=n;k++)if(equ(a*p[k].x*p[k].x+b*p[k].x,p[k].y)) vis[k]=true;break;}tot++;}ans=min(ans,tot);if(ans==1) break;}printf("%d\n",ans);
}
int main()
{srand(time(NULL));scanf("%d",&t);while(t--) work();return 0;
}

R=23333时:


R=46时:


后记:我好像用LaTeXLaTeX用上瘾了233

洛谷【P2831】愤怒的小鸟 (NOIP 2016 D2T3)相关推荐

  1. HOJ 系统常用功能介绍 部署快速入门 c++ python java编程语言在线自动评测 信息奥赛一本通 USACO GESP 洛谷 蓝桥 CSP NOIP题库

    技术支持微 makytony 服务器配置需求 腾讯云 2H4G 5M 60GB 轻量应用服务器  承载大约 200~400人使用,经过压力测试,评测并发速度可满足130人左右的在线比赛. 系统镜像选 ...

  2. 2018.11.01【NOIP2016】【洛谷P2831】愤怒的小鸟(状压DP)

    传送门 解析: 数据范围181818,多么显然的状压... 但是!!!为什么O(n22n)O(n^22^n)O(n22n)能过???复杂度明显不对啊... 这里提供一种O(n2n)O(n2^n)O(n ...

  3. 洛谷首页代码(百度编译器)

    洛谷是一个国内著名编程网站:分享一下他首页的未登录源代码: ​ <!DOCTYPE html> <html class="no-js" lang="zh ...

  4. 洛谷 P1948 [USACO08JAN]电话线Telephone Lines【NOIP模拟笨笨的电话线】

    [二分,spfa chenck] 题目描述 Farmer John wants to set up a telephone line at his farm. Unfortunately, the p ...

  5. 洛谷 - 试炼场(全部题目备份)

    整理的算法模板合集: ACM模板 目录 1.新手村 1 - 1 洛谷的第一个任务 1 - 2 顺序与分支 1 - 3 循环!循环!循环! 1 - 4 数组 1 - 5 简单字符串 1 - 6 过程函数 ...

  6. 洛谷 P1843 奶牛晒衣服

    题目背景 熊大妈决定给每个牛宝宝都穿上可爱的婴儿装 . 于是 , 为牛宝宝洗晒衣服就成了很不爽的事情. 题目描述 熊大妈请你帮助完成这个重任 . 洗完衣服后 , 你就要弄干衣服 . 衣服在自然条件下用 ...

  7. 【杂题总汇】NOIP2013(洛谷P1967) 货车运输

    [洛谷P1967] 货车运输 重做NOIP提高组ing... +传送门-洛谷P1967+ ◇ 题目(copy from 洛谷) 题目描述 A国有n座城市,编号从1到n,城市之间有m条双向道路.每一条道 ...

  8. java 判断一个数是正整数_【Java】P1075 质因数分解—关于数学方法在解题中的运用—(OJ:洛谷)...

    点击上方"蓝字"关注我们了解更多算法思路01题目 题目来源:洛谷OJ 题目链接: https://www.luogu.com.cn/ 题目描述 已知正整数n是两个不同的质数的乘积, ...

  9. 洛谷--P1067 多项式输出

    题目描述 一元nn次多项式可用如下的表达式表示: 其中,a_ix^iai​xi称为ii次项,a_iai​ 称为ii次项的系数.给出一个一元多项式各项的次数和系数,请按照如下规定的格式要求输出该多项式: ...

最新文章

  1. python开发的优秀界面-:Python做推荐系统,界面用什么实现
  2. Oracle序列的建立以及使用
  3. 变异蛮牛 树,dfs,二分图染色 牛客白月赛44
  4. 树莓派 docker homeassistant_利用树莓派追踪飞机航行轨迹的骚姿势分享(转载)
  5. Flutter 从配制开发环境再到开发第一个应用
  6. 数据科学入门与实战:玩转pandas之七数据分箱技术,分组技术,聚合技术
  7. static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?...
  8. CodeForces - 18A Triangle(数学?)
  9. kali linux的使用教程
  10. Linux C语言UDP实现视频文件上传
  11. 【趣闻】清华大学大一的英文原版线性代数教材里居然出现了Python
  12. 最小二乘法的曲线拟合
  13. IBus拼音无法选择候选词故障
  14. win7 x64部署和串口调试虚拟驱动toaster
  15. 我的抗争:一个中年编外程序员的挣扎
  16. 电脑桌面不见了怎么办?只能调出任务管理器!
  17. sklearn 中的Ridge函数
  18. margin-top不起作用???
  19. Mituan-极客时间-漏洞挖掘与智能攻防实战
  20. 计算机组织有CPU,计算机组织与结构 复习题 练习-cpu and memory(3页)-原创力文档...

热门文章

  1. 成功的项目经理,每天、每周、每旬、每月都做了什么?
  2. 8、核心交换机、DHCP
  3. linux fdisk等命令,fdisk命令详解
  4. what is SEO ?
  5. Spring Boot葵花宝典:初现江湖
  6. 中南大学计算机二级证书领取,中南大学本科生院医学教育办2011下半年全国计算机等考报名通知...
  7. 重生之我是赏金猎人(二)-逆向app破解数据包sign值实现任意数据重放添加
  8. eclipse下载安装教程
  9. 有一个设计时钟的题目,进行详细分析(一)
  10. 【Python成长之路】 文字转图片(白底黑字,无中文乱码)