愤怒的小鸟 NOIP2016 提高组 状压dp
Posted 行码棋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了愤怒的小鸟 NOIP2016 提高组 状压dp相关的知识,希望对你有一定的参考价值。
题目链接
大意:有许多小猪猪,现在小鸟从坐标原点出发,飞行轨迹为抛物线,问最少需要多少只小鸟才能打完所有的猪猪。
状压dp
把抛物线能够覆盖的小猪看成一个状态,比如说0101表示第1个和第三个小猪可以被抛物线覆盖,其余的不会
p
a
t
h
[
i
]
[
j
]
path[i][j]
path[i][j]表示经过第i
个和第j
个小猪的抛物线能够覆盖的状态
f
[
i
]
f[i]
f[i]表示在状态为i
时,需要的最小的抛物线的数目
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef pair<double,double> pii;//存储点的坐标
const int N = 20,M = 1<<18;
const double eps = 1e-6;//设置浮点比较的误差
pii p[N];
int n,m;
int path[N][N];
int f[M];
//比较浮点数的函数
bool cmp(double a,double b)
{
if(fabs(a-b)<eps) return true;
return false;
}
int main()
{
int _;
cin>>_;
while(_--)
{
cin>>n>>m;
for(int i=0;i<n;i++) cin>>p[i].fi>>p[i].se;
memset(path,0,sizeof(path));
for(int i=0;i<n;i++)
{
//经过单个点认为只经过自己
path[i][i] = 1<<i;
for(int j=0;j<n;j++)
{
double x1 = p[i].fi,y1 = p[i].se;
double x2 = p[j].fi,y2 = p[j].se;
if(cmp(x1,x2)) continue;
double a = (y1/x1 - y2/x2)/(x1-x2);
double b = y1/x1 - a*x1;
if(a>0 || cmp(a,0))continue; //保证斜率为负数
for(int k=0;k<n;k++)//已知抛物线的相关参数,枚举小猪,看抛物线是否经过
{
double x = p[k].fi, y = p[k].se;
if(cmp(a*x*x+b*x,y)) path[i][j] += 1<<k;//记录抛物线能够覆盖的小猪
}
}
}
memset(f,0x3f3f,sizeof f);
f[0] = 0;
for(int i=0;i< 1<<n;i++)
{
int x = 0;
for(int j=0;j<n;j++)
{
if(!(i >> j & 1))
{
x = j;
break;
}
}
for(int k=0;k<n;k++)
f[i|path[x][k]] = min(f[i|path[x][k]],f[i]+1);
}
cout<<f[(1<<n) - 1]<<'\\n';
}
return 0;
}
以上是关于愤怒的小鸟 NOIP2016 提高组 状压dp的主要内容,如果未能解决你的问题,请参考以下文章