计算最少的能够覆盖所有给定的点的抛物线数量。
暴搜思路
:
Int res = 0
Int dfs(int state)
{
If(所有列都包含)return 0;
枚举没有包含的点x
枚举包含 没有被包含的点 的抛物线
更新抛物线到new_state
Res = min( dfs (new_state) + 1, res)
Return res
}
状态定义:
state: 1001
表示点1, 4
f[state]
:覆盖state中点的最小抛物线数量
f[1001]
:覆盖点1, 4 的最小抛物线数量
抛物线:
path[x][y]
:x,y表示确定当前抛物线的两个点
Path[x][y] = 1001
, x , y确定的抛物线包括点1,4
f[new__ state] = f[state | 抛物线]
:更新包含state中点的抛物线数量
q[]
: 输入的点
状态计算:
f[i | path[x][j]] = min(f[i | path[x][j]] , f[i] + 1)
使用x, y 来确定一个抛物线y=ax^2+bx,
a=(y_1/x_1 −y_2/x_2 )/(x1 −x2)
b=y_1/x_1 −ax_1
步骤:
1.输入题目样例 不同小猪的坐标q[i]
2.确定抛物线, 更新path:
找两个点:x1 = q[i].x , y1 = q[i].y ,x2, y2
通过上述的公式,把抛物线方程的a, b求出来(x1 != x2)
枚举所有点,点在这条抛物线上时,更新path为state (状态压缩, 1表示有点)state表示;抛物线包含了哪些点
3.枚举所有的状态,遇到二进制位 = 0, 即点不在抛物线上的时候,记录这个点x
枚举所有的点j ,path[x][j]是包含点x的所有抛物线。
4.更新抛物线f[]
注意:
A < 0
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
#define x first
#define y second
typedef pair<double, double> PDD;
const int N = 20, M = 1 << N;
/*注意是double*/
const double def = 1e-8;
int f[M], path[N][N];
PDD q[N];
int cmp(double x, double y)
{
if(fabs(x - y) < def)return 0;
else if(x - y > 0)
return 1;
return -1;
}
int main()
{
int T; cin >> T;
while(T--)
{
memset(path, 0, sizeof path);
int n, m; cin >> n >> m;
for(int i = 0; i < n; ++i)
cin >> q[i].x >> q[i].y;
/*构造path抛物线*/
for(int i = 0; i < n; ++i)
{
/*不加这个?*/
/*那么当遇到只有一个点的时候,path无法更新,f会是初始值*/
path[i][i] = 1 << i;
for(int j = 0; j < n; ++j)
{
double a, b;
double x1 = q[i].x, y1 = q[i].y;
double x2 = q[j].x, y2 = q[j].y;
/*否则a 和 b都没法计算*/
if(!cmp(x1, x2))continue;
a = (y1 / x1 - y2 / x2) / (x1 - x2);
if(cmp(a, 0) >= 0)continue;
b = y1 / x1 - a * x1;
int state = 0;
/*判断所有在抛物线上的点*/
for(int k = 0; k < n; ++k)
{
double x = q[k].x, y = q[k].y;
if(!cmp(a * x * x + b * x, y))
/*更新state*/
state += 1 << k;
/*更新path*/
}
path[i][j] = state;
// cout << path[1][1] << endl;
}
}
/*为什么方程要单列出来?*/
/*第一次找到的是不在抛物线上的点,第二次找到和这个点在一条抛物线上的其他点*/
/*写成 i < 1 << n 可以吗?*/
/*可以,多计算一次而已*/
// 为什么要break?
/*不加也可以,不过找到的是state二进制中 从右到左 最后一个不在抛物线上的点*/
memset(f, 0x3f, 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;
}
}
for(int j = 0; j < n; ++j)
f[i | path[x][j]] = min(f[i | path[x][j]], f[i] + 1);
}
cout << f[(1 << n) - 1] <<endl;
}
return 0;
}