P2831 [NOIP2016 提高组] 愤怒的小鸟

思路

状压+优化

代码

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string>
#include <cmath>
#include <string.h>
#define R(x) x = read()
#define For(i, j, n) for (int i = j; i <= n; ++i)
using namespace std;

const int N = 20, M = 1 << 18;
const double eps = 1e-8;

void equation(double &x, double &y, double a1, double b1, double c1, double a2, double b2, double c2)
{ // 解方程
    y = (a1 * c2 - a2 * c1) / (a1 * b2 - a2 * b1);
    x = (c1 - b1 * y) / a1;
}

bool Equal(double a, double b)
{
    if (fabs(a - b) < eps)
        return true;
    return false;
}

bool check(double x, double y, double a, double b)
{
    return Equal(y, a * x * x + b * x);
}

// equation(a,b,x[i]*x[i],x[i],y[i],x[j]*x[j],x[j],y[j]);

int t, n, m;
int Connection[N][N], f[M], first_zero[M];
double x[N], y[N];

int lowbit(int x)
{
    return x & (-x);
}

void print(int x)
{
    for (int i = 7; i >= 0; i--)
        cout << ((x >> i) & 1);
    cout << endl;
}

void get_zero()
{
    for (int i = 0; i < M; i++)
    {
        for (int j = 0; j < 18; j++)
        {
            if (!((i >> j) & 1))
            {
                first_zero[i] = j;
                break;
            }
        }
    }
}

void init()
{
    double a, b;
    memset(Connection, 0, sizeof(Connection));
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
        {
            if (i == j)
            {
                Connection[i][i] = 1 << (i - 1);
                continue;
            }
            if (Equal(x[i], x[j]))
                continue;
            equation(a, b, x[i] * x[i], x[i], y[i], x[j] * x[j], x[j], y[j]);
            if (a > -eps)
                continue;
            for (int k = 1; k <= n; k++)
                if (check(x[k], y[k], a, b))
                    Connection[i][j] |= 1 << (k - 1);
        }
}

int dp()
{
    memset(f, 0x3f, sizeof(f));
    f[0] = 0;
    for (int st = 0; st < 1 << n; st++)
    {
        int p = first_zero[st];
        for (int i = 1; i <= n; i++)
        {
            int t = st | Connection[p + 1][i];
            f[t] = min(f[t], f[st] + 1);
        }
    }
    return f[(1 << n) - 1];
}

int main()
{
    get_zero();
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%d", &n, &m);
        For(i, 1, n)
            scanf("%lf%lf", &x[i], &y[i]);
        init();
        printf("%d\n", dp());
    }
    return 0;
}

 细节

get_zero函数:

void get_zero()
{
    for (int i = 0; i < M; i++)
    {
        for (int j = 0; j < 18; j++)
        {
            if (!((i >> j) & 1))
            {
                first_zero[i] = j;
                break;
            }
        }
    }
}

get_zero()函数的作用是预处理所有数字的第一个0在哪(类似于lowbit)

还有一种做法:

void get_zero()
{
    
    Log[0] = -1;
    For(i, 1, M)
        Log[i] = Log[i >> 1] + 1;
    for(int i = 0; i < M; i++)
    {
        int t = ~i;
        t = lowbit(t);
        first_zero[i] = Log[t];
    }
}

dp过程:

for (int st = 0; st < 1 << n; st++)
    {
        int p = first_zero[st];
        for (int i = 1; i <= n; i++)
        {
            int t = st | Connection[p + 1][i];
            f[t] = min(f[t], f[st] + 1);
        }
    }
    return f[(1 << n) - 1];
}

这里从first_zero开始枚举,相当于dfs中的排除等效冗余

 

posted @ 2024-04-03 11:49  Gold_stein  阅读(6)  评论(0编辑  收藏  举报