HDU 3362 Fix

状压DP。

首先很容易想到:一个点要被固定的话,必须有两个已经固定了的点与这个点连边。

再看N的范围,秒想到状压DP,秒出思路。1表示这个点已经被固定,0表示还没被固定。

推导某个状态的时候,枚举一下这个状态下所有被固定的点哪个是最后被固定的,即可得出这个状态的最优解。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

int n;
struct Point
{
    int x;
    int y;
    int flag;
}p[20];
double dp[600000];
double dis[20][20];
double tmp[20];
int base[20];

bool cmp(const Point&a, const Point&b)
{
    return a.flag>b.flag;
}

void read()
{
    for (int i = 0; i<n; i++)
        scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].flag);
    sort(p, p + n, cmp);
}

void init()
{
    for (int i = 0; i < (1 << n) + 10; i++) dp[i] = 999999999.0;
    
    for (int i = 0; i<n; i++)
    {
        for (int j = 0; j<n; j++)
        {
            if (i == j) dis[i][j] = 999999999.0;
            else dis[i][j] = sqrt((p[i].x - p[j].x)*(p[i].x - p[j].x) + (p[i].y - p[j].y)*(p[i].y - p[j].y));
        }
    }
}

void work()
{
    int pos = -1;
    for (int i = 0; i<n; i++)
    {
        if (p[i].flag==1) pos = i;
        else break;
    }

    if (pos == -1) printf("No Solution
");
    else if (pos+1 < 2 )
    {
        if (n != pos + 1) printf("No Solution
");
        else printf("0.000000
");
    }
    else
    {
        for (int i = 0; i<(1 << (pos + 1)); i++) dp[i] = 0;
        for (int i = pos + 1; i<n; i++)
        {
            int state = (1 << (pos + 1)) - 1 + (1 << i);
            for (int k = 0; k <= pos; k++) tmp[k] = dis[i][k];
            sort(tmp, tmp + pos + 1);
            dp[state] = tmp[0] + tmp[1];
        }

        for (int i = (1 << (pos + 1)); i<(1 << n); i++)
        {
            if (dp[i] != 999999999.0) continue;

            int temp = i, tot = 0;
            while (temp) base[tot++] = temp % 2, temp = temp / 2;

            bool fail = 0;
            for (int k = 0; k <= pos; k++) if (!base[k]) fail = 1;
            if (fail) continue;

            for (int k = pos + 1; k < tot; k++)
            {
                if (base[k])
                {
                    int u = 0;
                    for (int s = 0; s<tot; s++)
                    {
                        if (s == k) continue;
                        if (base[s]) tmp[u++] = dis[k][s];
                    }
                    sort(tmp, tmp + u);
                    dp[i] = min(dp[i], dp[i - (1 << k)] + tmp[0] + tmp[1]);
                }
            }
        }
        printf("%.6lf
", dp[(1 << n) - 1]);
    }
}

int main()
{
    while (~scanf("%d", &n))
    {
        if (!n) break;
        read();
        init();
        work();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zufezzt/p/5197622.html