HDU 4892 Defence of the Trees

首先最优解肯定是一个凸多边形,如果是凹多边形的话我们把凹的地方补上可以得到不更差的答案。

一个凸多边形一定存在一种类似链结构的三角剖分,即如果我们把三角形当作点,有两个公共顶点的三角形之间连边的话,一定存在一种三角剖分使得三角形呈一个链结构。

    所以最优解一定可以被表示成一个由C(m,3)个三角形组成的图中的一条链,把三角形A到三角形B的边权定义为三角形 B 的其他两边长度减去公共边长度,原问题转化为给定一个无向图,点上有标记(可能多个,找一条包含所有 k 种标记的最短路。直接状压 + 类似最短路转移即可。

Defence of the Trees

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 235    Accepted Submission(s): 57
Special Judge


Problem Description
There are n trees (each of them can be considered as a point) on a two-dimensional coordinate system. There are k categories of trees, category of the i th tree are represented by A i. There are also m stumps (each of them can be considered as a point, too) on this two-dimensional coordinate system. Stumps can be connected with straight wires.

Your task is to connect some of the stumps by wires to build exactly one simple polygon (that is, a polygon without self-intersection and degeneration) which contains trees of all k categories inside. Meanwhile, in order to save money, you should make the total length of wires as short as possible. Your task is to calculate the shortest total length of wires, or to determine that there is no solutions.
 

Input
There are several testcases, please process till EOF.

In each testcases:
First one line, three numbers n, m, k. Following n lines contains n 2D-coordinates describing each tree. Next one line contains n number, where i th number A i denotes i th tree's category. Next m lines describe the coordinates of stumps, you may assume that there is no trees lying on segments between any two stumps.

All input will be integer, and absolute value of them will be less than 23333, 1 ≤ n ≤ 300, 1 ≤ m ≤ 40, 1 ≤ k ≤ 6,1 ≤ A i ≤ k.In about 90% of testcases,m ≤ 10.
 

Output
For each testcase, print one line, if there is no solutions, Output "Impossible" (without quotes), else output a real number indicating the minimal total length. Your answer will be considered correct if and only if the absolute error or relative error are less than 10 -6.
 

Sample Input
     
     
     
     
2 4 1 0 0 2 0 1 1 1 -1 1 1 -3 -1 5 1 2 4 2 0 0 2 0 1 2 1 -1 1 1 -3 -1 5 1
 

Sample Output
     
     
     
     
10.472135955000 16.944271909999
 

Author
Fudan University
 

Source
2014 Multi-University Training Contest 3
 
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define prt(k) cout<<#k" = "<<k<<endl
#include <cmath>
#include <algorithm>
const int N = 333;
const int M = 41;
const int MAXN = 12111;     /// Max number of Triangles
int sqr(int x) { return x * x; }
struct P
{
    double x, y; int t;
    P() {}
    P(double _x, double _y) { x=_x, y=_y; }
    double dis(P b)
    {
        return sqrt((x-b.x)*(x-b.x)+(y-b.y)*(y-b.y));
    }
    double operator * (P b)
    {
        return x*b.y - y*b.x;
    }
    P operator - (P b) { return P(x-b.x,y-b.y); }
}p[454];
double dis(P a, P b) { return a.dis(b); }
int n, m, kind;
P a[334], b[545];
const double inf = 1e18;
const double eps = 1e-8;
double cross(P a, P b) { return a * b; }
double cross(P a, P b, P c) { return (b - a) * (c - a); }
int cmp(double x) { return x < -eps ? -1 : x > eps; }
bool in(P p, P a, P b, P c)
{
    double t = fabs(cross(p,a,b)) + fabs(cross(p,b,c)) + fabs(cross(p,a,c));
    return cmp(t - fabs(cross(a,b,c))) == 0;
}
int side(P a, P b, P s, P t)
{
    return cmp(cross(s,a,t) * cross(s,b,t));
}
int mask[MAXN];
int id[M][M][M];
int getID(int i, int j, int k)
{
    int a[3];
    a[0] = i, a[1] = j, a[2] = k;
    sort(a, a+3);
    return id[a[0]][a[1]][a[2]];
}
double w[M][M];
const int E = 1012000;
int to[E], next[E]; double cost[E];
int head[MAXN];
int tot;
void initEdge()
{
    tot = 0;
    memset(head, -1, sizeof head);
}
void addEdge(int u, int v, double w)
{
    to[tot] = v, cost[tot] = w;
    next[tot] = head[u];
    head[u] = tot++;
}
double d[66][MAXN];
#include <queue>
int cnt;    ///Triangles
bool inq[MAXN];
void spfa(double d[], int n)
{

    queue<int> q;
    for(int i=0;i<n;i++) inq[i] = true, q.push(i);
    while(!q.empty())
    {
        int u=q.front(); q.pop();   inq[u] = false;     /// balabala
        for(int i=head[u];~i;i=next[i])
        {
            int v = to[i];
            if(d[v] > d[u] + cost[i] + eps)
            {
                d[v] = d[u] + cost[i];
                if(!inq[v])
                {
                    inq[v] = true;
                    q.push(v);
                }
            }
        }
    }
}
double solve()
{
    memset(inq, 0, sizeof inq);
    for(int S=0;S<(1<<kind);S++)
    {
        spfa(d[S], cnt);
        for(int u=0;u<cnt;u++)
        {
            for(int e=head[u];~e;e=next[e])
            {
                int v = to[e];
                d[S|mask[v]][v] = min(d[S|mask[v]][v], d[S][u] + cost[e]);
            }
        }
    }
    double ans = inf;
    for(int i=0;i<cnt;i++) ans = min(ans, d[(1<<kind)-1][i]);
    return ans;
}
int main()
{
    while(scanf("%d%d%d", &n, &m, &kind)==3)
    {
        initEdge();
        for(int i=0;i<n;i++) scanf("%lf%lf", &a[i].x, &a[i].y);
        for(int i=0;i<n;i++) scanf("%d", &a[i].t), a[i].t--;
        for(int i=0;i<m;i++) scanf("%lf%lf", &b[i].x, &b[i].y), p[i] = b[i];
        cnt = 0;
        memset(mask, 0, sizeof mask);
        for(int i=0;i<m;i++)
        {
            w[i][i] = 0;
            for(int j=i+1;j<m;j++)
                w[i][j] = w[j][i] = dis(p[i], p[j]);
        }

        for(int i=0;i<m;i++)
        {
            for(int j=i+1;j<m;j++)
            {
                for(int k=j+1;k<m;k++)
                {
                    mask[cnt] = 0;
                    for(int t = 0; t < n; t++)
                    {
                        int id = a[t].t;
                     ///   if(mask[cnt]&(1<<id)) continue;
                        if(in(a[t], b[i],b[j],b[k]))
                        {
                            mask[cnt] |= (1<<id);
                        ///    printf("t = %d : %d %d %d\n", t, i, j, k);
                        }
                    }
                    for(int t=0;t<(1<<kind);t++) d[t][cnt] = inf;
                    d[mask[cnt]][cnt] = w[i][j] + w[j][k] + w[i][k];
                    id[i][j][k] = cnt++;
                }
            }
        }
        for(int i=0;i<m;i++)
        {
            for(int j=i+1;j<m;j++)
            {
                for(int k=0;k<m;k++)
                {
                    for(int t=k+1;t<m;t++)
                    {
                        if(k==i||k==j||t==i|t==j) continue;
                        if(side(p[k], p[t], p[i], p[j]) != -1) continue;
                       /// printf("%d %d : %d %d\n", i, j, k ,t);
                        int u = getID(i, j, k);
                        int v = getID(i, j, t);
                        addEdge(u, v, w[i][t] + w[t][j] - w[i][j]);
                        addEdge(v, u, w[i][k] + w[k][j] - w[i][j]);
                    }
                }
            }
        }

        double ans = solve();

        if(cmp(ans - inf) >= 0) printf("Impossible\n");
        else printf("%.12f\n", ans);
    }
    return 0;
}



你可能感兴趣的:(HDU 4892 Defence of the Trees)