2010-1079

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

== 题意 ==
有N个炮塔要打M个目标。一颗炮弹发射后需要T1才能离开炮塔,一颗炮弹发射完后需要T2时间才能发射下一刻。炮弹的飞行速度为V,给定各个炮塔和各个目标的坐标,求最少需要多少时间才能打中所有目标。

== 题解 ==
二分时间,然后根据时间建立二分图,把一个炮塔拆成好几个点,分别表示第1次发射,第2次发射……如果某次发射能击中目标,则连一条边到表示目标的点上。求一下最大匹配,如果最大匹配是M,则继续二分左边的区间[left,middle], 否则则二分区间[middle, right]。

== 代码 ==

{{{
#!cpp
#include <iostream>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define MAXN 64
#define MAXM 64
#define MAXSZ MAXN*MAXM
using namespace std;
class Hungary {
    vector<int> e[MAXN];
    int n, m, match[MAXN], rmatch[MAXM];
    bool vis[MAXN];
    bool _augment(int u) {
        if(!vis[u]) {
            vis[u] = true;
            vector<int>::iterator it;
            for(it = e[u].begin(); it != e[u].end(); ++it) {
                if(rmatch[*it] == -1 || _augment(rmatch[*it])) {
                    match[u] = *it;
                    rmatch[*it] = u;
                    return true;
                }
            }
        }
        return false;
    }
public:
    void init(int n) {
        this->n = n;
        for(int i = 0; i < n; ++i)
            e[i].clear();
    }
    void addEdge(int u, int v) {
        e[u].push_back(v);
    }
    int maxMatch(int m) {
        this->m = m;
        int cnt = 0;
        fill(match, match + n, -1);
        fill(rmatch, rmatch + m, -1);
        for(int i = 0; i < n; ++i) {
            fill(vis, vis + n, false);
            if(_augment(i)) {
                ++cnt;
            }
        }
        return cnt;
    }
} h;
class IDSet {
    int data[MAXSZ];
    int sz;
public:
    void init(int n) {
        fill(data, data + n, -1);
        sz = 0;
    }
    int getId(int num) {
        if(data[num] == -1) {
            data[num] = sz++;
        }
        return data[num];
    }
    int size() {
        return sz;
    }
} ids;
int main() {
    int n, m, v;
    double t1, t2;
    int tx[MAXM], ty[MAXM];
    double d[MAXN][MAXM];
    while(scanf("%d%d%lf%lf%d", &n, &m, &t1, &t2, &v) != EOF) {
        t1 /= 60;
        for(int i = 0; i < m; ++i)
            scanf("%d%d", &tx[i], &ty[i]);
        double maxt = 0;
        for(int i = 0; i < n; ++i) {
            int x, y;
            scanf("%d%d", &x, &y);
            for(int j = 0; j < m; ++j) {
                d[i][j] = hypot(x - tx[j], y - ty[j]) / v;
                maxt = max(maxt, d[i][j]);
            }
        }
        double le = 0, ri = (m + n - 1) / n * (t1 + t2) + maxt;
        //printf("%lf %lf\n", le, ri);
        while(ri - le > 1e-7) {
            double mi = (le + ri) / 2;
            ids.init(n * m);
            h.init(m);
            for(int i = 0; i < n; ++i) {
                for(int j = 0; j < m; ++j) {
                    double t = t1;
                    for(int k = 0; k < m && t + d[i][j] <= mi; ++k) {
                        //printf("%d %d %d\n", i, k, j);
                        h.addEdge(j, ids.getId(i * m + k));
                        t += t1 + t2;
                    }
                }
            }
            int ret = h.maxMatch(ids.size());
            //printf("%lf %lf %d %d\n", le, ri, ret, m);
            if(ret == m)
                ri = mi;
            else
                le = mi;
        }
        printf("%.6lf\n", le);
    }
}
}}}

题意

有N个炮塔要打M个目标。一颗炮弹发射后需要T1才能离开炮塔,一颗炮弹发射完后需要T2时间才能发射下一刻。炮弹的飞行速度为V,给定各个炮塔和各个目标的坐标,求最少需要多少时间才能打中所有目标。

题解

二分时间,然后根据时间建立二分图,把一个炮塔拆成好几个点,分别表示第1次发射,第2次发射……如果某次发射能击中目标,则连一条边到表示目标的点上。求一下最大匹配,如果最大匹配是M,则继续二分左边的区间[left,middle], 否则则二分区间[middle, right]。

代码

#include <iostream>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define MAXN 64
#define MAXM 64
#define MAXSZ MAXN*MAXM
using namespace std;
class Hungary {
    vector<int> e[MAXN];
    int n, m, match[MAXN], rmatch[MAXM];
    bool vis[MAXN];
    bool _augment(int u) {
        if(!vis[u]) {
            vis[u] = true;
            vector<int>::iterator it;
            for(it = e[u].begin(); it != e[u].end(); ++it) {
                if(rmatch[*it] == -1 || _augment(rmatch[*it])) {
                    match[u] = *it;
                    rmatch[*it] = u;
                    return true;
                }
            }
        }
        return false;
    }
public:
    void init(int n) {
        this->n = n;
        for(int i = 0; i < n; ++i)
            e[i].clear();
    }
    void addEdge(int u, int v) {
        e[u].push_back(v);
    }
    int maxMatch(int m) {
        this->m = m;
        int cnt = 0;
        fill(match, match + n, -1);
        fill(rmatch, rmatch + m, -1);
        for(int i = 0; i < n; ++i) {
            fill(vis, vis + n, false);
            if(_augment(i)) {
                ++cnt;
            }
        }
        return cnt;
    }
} h;
class IDSet {
    int data[MAXSZ];
    int sz;
public:
    void init(int n) {
        fill(data, data + n, -1);
        sz = 0;
    }
    int getId(int num) {
        if(data[num] == -1) {
            data[num] = sz++;
        }
        return data[num];
    }
    int size() {
        return sz;
    }
} ids;
int main() {
    int n, m, v;
    double t1, t2;
    int tx[MAXM], ty[MAXM];
    double d[MAXN][MAXM];
    while(scanf("%d%d%lf%lf%d", &n, &m, &t1, &t2, &v) != EOF) {
        t1 /= 60;
        for(int i = 0; i < m; ++i)
            scanf("%d%d", &tx[i], &ty[i]);
        double maxt = 0;
        for(int i = 0; i < n; ++i) {
            int x, y;
            scanf("%d%d", &x, &y);
            for(int j = 0; j < m; ++j) {
                d[i][j] = hypot(x - tx[j], y - ty[j]) / v;
                maxt = max(maxt, d[i][j]);
            }
        }
        double le = 0, ri = (m + n - 1) / n * (t1 + t2) + maxt;
        //printf("%lf %lf\n", le, ri);
        while(ri - le > 1e-7) {
            double mi = (le + ri) / 2;
            ids.init(n * m);
            h.init(m);
            for(int i = 0; i < n; ++i) {
                for(int j = 0; j < m; ++j) {
                    double t = t1;
                    for(int k = 0; k < m && t + d[i][j] <= mi; ++k) {
                        //printf("%d %d %d\n", i, k, j);
                        h.addEdge(j, ids.getId(i * m + k));
                        t += t1 + t2;
                    }
                }
            }
            int ret = h.maxMatch(ids.size());
            //printf("%lf %lf %d %d\n", le, ri, ret, m);
            if(ret == m)
                ri = mi;
            else
                le = mi;
        }
        printf("%.6lf\n", le);
    }
}