Cod sursa(job #1026804)

Utilizator romircea2010FMI Trifan Mircea Mihai romircea2010 Data 12 noiembrie 2013 00:12:41
Problema Popandai Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 5.14 kb
#include <iostream>
#include <fstream>
#include <algorithm>
#define INF 2000000000
#define lim 1000000
#define Next ++position == lim?f.read(buffer, lim), position = 0:0
#define NMax 310
#define KMax 310

using namespace std;

/**de impartit aria la 2 !!*/

int sol = INF;
int stanga[NMax], dreapta[NMax];
int nrunder[NMax][NMax];
int n, K;
ifstream f ("popandai.in");
int position;
char buffer[lim];
struct punct
{
    int x, y;
    punct()
    {
        x = y = 0;
    }
    punct (const int _x, const int _y)
    {
        x = _x;
        y = _y;
    }
    bool operator < (const punct &other) const
    {
        if (x == other.x)
            return y > other.y;
        return x < other.x;
    }
};
punct a[NMax];

inline void Read(int &x)
{
    for (; buffer[position] < '0' || buffer[position] > '9'; Next);
    for (x = 0; '0' <= buffer[position] && buffer[position] <= '9'; x = x*10 + buffer[position] - '0', Next);
}

void Read()
{
    Read(n), Read(K);
    int x, y, i;
    for (i=1; i<=n; ++i)
    {
        Read(x), Read(y);
        a[i] = punct(x, y);
    }
}

inline int Determinant(const punct A, const punct B, const punct C)
{
    ///return a[i].y * a[k].x + a[j].x * a[k].y + a[i].x * a[j].y - a[i].y * a[j].x - a[j].y * a[k].x - a[i].x * a[k].y;
    return A.y * C.x + B.x * C.y + A.x * B.y - A.y * B.x - B.y * C.x - A.x * C.y;
}

inline int NrPuncte(const int i, const int j, const int k)
{
    /// i < j deci asta inseamna ca a[i].x < a[j].x; daca a[i].x == a[j].x atunci a[i].y > a[j].y
    /// tin punctele in ordine dupa x si ma uit doar la pozitia punctului din mijloc, daca e deasupra
    /// sau sub dreapta data de st si dr si in functie de asta calculez cu formulele de mai jos.
    int st, mij, dr;
    if (k < i)
        st = k, mij = i, dr = j;
    else
    {
        st = i;
        if ( k < j )
            mij = k, dr = j;
        else
            mij = j, dr = k;
    }
    if (Determinant(a[st], a[dr], a[mij]) > 0)
        return nrunder[st][mij] + nrunder[mij][dr] - nrunder[st][dr];
    return nrunder[st][dr] - nrunder[st][mij] - nrunder[mij][dr] - 1;
}


inline int Aria(const punct A, const punct B, const punct C)
{
    return abs(A.y * C.x + B.x * C.y + A.x * B.y - A.y * B.x - B.y * C.x - A.x * C.y);
}

void Precalc()
{
    int i, j, k;
    for (i=1; i<=n; ++i)
        for (j=i+1; j<=n; ++j)
            for (k = 1; k<j; ++k)
                if ((min(a[i].x, a[j].x) <= a[k].x && a[k].x < max(a[i].x, a[j].x)) && (Determinant(a[i], a[j], a[k]) < 0))
                    ++nrunder[i][j];
}

void Solve()
{
    /// sortez punctele crescator dupa x si in caz de egalitate, descrescator dupa y
    sort(a+1, a+n+1);

    /// precalculez in nrunder[i][j] cate puncte sunt sub segmentul [i, j) cu i < j
    Precalc();
    int i, j, k, det;
    /**
    pentru fiecare segment (i, j) fixat iau oricare al 3 lea punct si calculez aria triunghiului format
    precum si cate puncte are in interior. Retin triunghiurile in 2 grupe reprezentand cele 2 semiplanuri
    create de dreapta (i, j) stanga[..] respectiv dreapta[..]
    stanga[x] = aria minima a unui triunghi care are in interior x puncte,
                acest triunghi aflandu-se in semiplanul din stanga
    dreapta[x] = aria minima a unui triunghi care are in interior x puncte,
                acest triunghi aflandu-se in semiplanul din dreapta
    Daca as avea fix K puncte in interior atunci as lua x puncte din stanga si K - x puncte din dreapta
    dar cum imi trebuie cel putin K puncte si arie minima, prefer ca pentru un dreapta[x] de exemplu
    sa aleg un dreapta[y] cu y>x si dreapta[y] < dreapta[x] (analog si cu stanga)
    deci fac minime partiale de la n spre 1
    si solutia = min(stanga[x] + dreapta[K-x]) , x de la 0 la K pentru orice i, j fixat; i<j
    */

    for (i=1; i<=n; ++i)
    {
        for (j=i+1; j<=n; ++j)
        {
            for (k=0; k<=n; ++k)
                stanga[k] = dreapta[k] = INF;
            for (k=1; k<=n; ++k)
            {
                if (k == i || k == j)
                    continue;
                det = Determinant(a[i], a[j], a[k]);
                if (det > 0)
                {
                    /// stanga
                    int nrpoints = NrPuncte(i, j, k);
                    stanga[nrpoints] = min(stanga[nrpoints], Aria(a[i], a[j], a[k]));
                }
                else
                {
                    ///dreapta
                    int nrpoints = NrPuncte(i, j, k);
                    dreapta[nrpoints] = min(dreapta[nrpoints], Aria(a[i], a[j], a[k]));
                }
            }
            for (k=n; k; --k)
                stanga[k-1] = min(stanga[k-1], stanga[k]),
                dreapta[k-1] = min(dreapta[k-1], dreapta[k]);
            for (k = 0; k <= K; ++k)
                if (stanga[k] != INF && dreapta[K-k] != INF)
                    sol = min (sol, stanga[k] + dreapta[K-k]);
        }
    }
}

void Write()
{
    FILE *g = fopen ("popandai.out", "w");
    fprintf(g, "%.1lf\n", 1.0*sol/2);
    fclose(g);
}

int main()
{
    Read();
    Solve();
    Write();
    return 0;
}