JoyOI1935 导弹防御塔

原题链接

首先可以二分答案,然后考虑检验答案。
我们可以对炮塔进行拆点,即能发射\(x\)颗导弹就拆成\(n\times x\)个点,作为一个集合,另一个集合则是\(m\)个侵入者,然后对于能在剩余时间攻击到侵入者的炮弹和该侵入者连边,然后跑匈牙利或网络流求二分图最大匹配即可(本质是多重匹配,使用拆点法)。

#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
const int N = 55;
const int M = 1e6 + 10;
const int K = 1e5 + 10;
struct dd {
    double x, y;
};
dd a[N], b[N];
int fi[K], di[M], ne[M], mtc[K], l, t_2, n, m;
double dis[N][N], t_1;
bool v[K];
inline int re()
{
    int x = 0;
    char c = getchar();
    bool p = 0;
    for (; c < '0' || c > '9'; c = getchar())
        p |= c == '-';
    for (; c >= '0' && c <= '9'; c = getchar())
        x = x * 10 + c - '0';
    return p ? -x : x;
}
inline void add(int x, int y)
{
    di[++l] = y;
    ne[l] = fi[x];
    fi[x] = l;
}
bool dfs(int x)
{
    int i, y;
    for (i = fi[x]; i; i = ne[i])
        if (!v[y = di[i]])
        {
            v[y] = 1;
            if (!mtc[y] || dfs(mtc[y]))
            {
                mtc[y] = x;
                return true;
            }
        }
    return false;
}
bool judge(double mid)
{
    int i, j, s = 0, k = 0;
    double T = mid;
    memset(fi, 0, sizeof(fi));
    memset(mtc, 0, sizeof(mtc));
    l = 0;
    while (T >= t_1)
    {
        T -= t_1;
        k++;
        for (i = 1; i <= m; i++)
            for (j = 1; j <= n; j++)
                if (dis[j][i] <= T)
                    add(i, (k - 1) * n + j);
        T -= t_2;
    }
    for (i = 1; i <= m; i++)
    {
        memset(v, 0, sizeof(v));
        if (dfs(i))
            s++;
    }
    return !(s ^ m);
}
int main()
{
    int i, j, x, y, V;
    double l, r = 3e4, mid;
    n = re();
    m = re();
    l = t_1 = re() * 1.0 / 60;
    t_2 = re();
    V = re();
    for (i = 1; i <= m; i++)
    {
        a[i].x = re();
        a[i].y = re();
    }
    for (i = 1; i <= n; i++)
    {
        x = re();
        y = re();
        for (j = 1; j <= m; j++)
            dis[i][j] = sqrt(1.0 * (x - a[j].x) * (x - a[j].x) + 1.0 * (y - a[j].y) * (y - a[j].y)) / V;
    }
    while (l + 1e-7 < r)
    {
        mid = (l + r) / 2;
        if (judge(mid))
            r = mid;
        else
            l = mid;
    }
    printf("%.6f", r);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Iowa-Battleship/p/9642609.html