[Nowcoder 2018ACM多校第二场F] trade

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013578420/article/details/81172419

题目大意:
给出n个仓库, 初始时有a[i]个货物, 有m轮订单依次进行, 对于第i轮订单, 货车一开始为空, 然后货车从依次经过仓库x[i][0…s[i]-1], 在每个仓库可以选择装上或是卸下任意多的产品, 最后到达该订单目的地, 目的地最多收lim[i]个货物。 同时有k个干扰器, 每个干扰器有个半径r[i], 若在某轮订单中, 经过的某个仓库和目的地连线与圆相交或相切, 则会在该轮订单被跳过。 保证没有点一开始就在某个干扰器的圆中。求一共能卖出最多多少货物。 ( n , m 10 3 , a l l n u m b e r 10 9 )

题目思路:
首先对于干扰器其实就是求线段与圆相交的问题, 这个可以一开始处理掉, 之后就是没有干扰器的版本。
对于第i轮订单, 维护一个e[i][j]表示, 根据前i轮订单, j的货物可以运到i, 初始时e[i][i] = 1, 然后每一轮订单, 更新e[x[i][j]][k] |= e[x[i][j-1]][k], 最后所有e[x[i][s[i] - 1]][j]为1的j都可以看作能在第i轮订单卖出去, 这里的操作需要用bitset加速。
然后就是网络流问题了,还是一个二分图的最大流问题。 s向每个仓库点连一条流量为a[i]的边, 每个订单点向t连一条流量为lim[i]的边, 仓库点与订单点的连边关系如上文所述, 连流量为inf。 最后最大流就是答案。

PS: 关于圆与线段判相交
现求出圆心到线段的垂足, 如果垂足在线段内,则拿垂足与圆心距离和半径比较; 否则, 线段两端点距圆心最小距离与半径比较。

Code:

#include <map>
#include <set>
#include <map>
#include <bitset>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define ll long long
#define db double
#define id(i, j) (((i) - 1) * m + j)
#define pw(x) ((x) * (x))

#define eps 1e-8

const int N = (int)2e3 + 10;
const int M = (int)4e6 + 10;
const ll inf = 1ll << 60;

int n, m, k;
db x1[N], Y1[N];
db x3[N], y3[N], r[N];
db x2[N], y2[N];
bitset<N>  e[N];

struct Point{
    db x, y;
    Point(db _x, db _y){x = _x, y = _y;}
    db len(){return sqrt(x * x + y * y);}
    Point operator-(const Point &_){
        return Point(x - _.x, y - _.y);
    }
    db operator*(const Point &_){
        return x * _.y - y * _.x;
    }
    db operator%(const Point &_){
        return x * _.x + y * _.y;
    }

};

bool ok(int i, int id){

    for (int h = 1; h <= k; h ++){
        Point A = Point(x1[id], Y1[id]), B = Point(x2[i], y2[i]), P = Point(x3[h], y3[h]);

        Point result(0, 0);//线段上离圆心最近点
        db t = ((P - A) % (B - A)) / ((B - A) % (B - A)); //AP 在BA 上的映射比例
        if (t >= 0 && t <= 1){
            result = Point(A.x + (B.x - A.x) * t, A.y + (B.y - A.y) * t);
        }
        else{
            if ((P - A) % (P - A) < (P - B) % (P - B))
                result = A;
            else
                result = B;
        }

        if ((P - result) % (P - result) < r[h] * r[h] + eps) return 0;

    }


    return 1;
}

int S, T;
int cnt = 1, lst[N * 2], cur[N * 2], nxt[M], to[M];ll f[M];
void add(int u, int v, ll flow){
    nxt[++ cnt] = lst[u]; lst[u] = cnt; to[cnt] = v; f[cnt] = flow;
    nxt[++ cnt] = lst[v]; lst[v] = cnt; to[cnt] = u; f[cnt] = 0;
}

int head, tail, que[N * 2], d[N * 2];
bool bfs(){
    head = 0;
    que[tail = 1] = S;
    for (int i = 1; i <= T; i ++) d[i] = 0;
    d[S] = 1;

    while (head < tail){
        int u = que[++ head];
        for (int j = lst[u]; j; j = nxt[j]){
            int v = to[j];
            if (d[v] || !f[j]) continue;

            d[v] = d[u] + 1;

            if (v == T) return 1;
            que[++ tail] = v;
        }
    }

    return 0;
}

ll dfs(int u, ll flow){
    ll a, ret = 0;
    if (u == T) return flow;
    for (int &j = lst[u]; j; j = nxt[j]){
        int v = to[j];
        if (f[j] && flow && d[v] == d[u] + 1 && (a = dfs(v, min(flow, f[j])))){
            ret += a, flow -= a;
            f[j] -=a, f[j ^ 1] += a;
        }
    }

    return ret;
}

int main(){
    scanf("%d %d %d", &n, &m, &k);

    S = n + m + 1, T = S + 1;

    for (int i = 1, a; i <= n; i ++){
        scanf("%lf %lf %d", x1 + i, Y1 + i, &a);
        add(S, i, a);
        e[i][i] = 1;
    }

    for (int i = 1; i <= k; i ++)
        scanf("%lf %lf %lf", x3 + i, y3 + i, r + i);

    for (int i = 1, nn, lim; i <= m; i ++){
        scanf("%lf %lf %d %d", x2 + i, y2 + i, &nn, &lim);
        add(n + i, T, lim);

        int now = 0, last = 0;
        for (int j = 1; j <= nn; j ++){

            scanf("%d", &now);
            if (!ok(i, now)) continue;

            if (last) e[now] |= e[last];
            last = now;
        }

        if (last){
            for (int j = 1; j <= n; j ++)
                if (e[last][j]){
                    add(j, n + i, inf);
                }
        }

    }

    ll ans = 0;
    while (bfs()){
        ll res = 0;
        memcpy(cur, lst, sizeof(lst));
        while (res = dfs(S, inf)) ans += res;
        memcpy(lst, cur, sizeof(lst));
    }

    printf("%lld\n", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u013578420/article/details/81172419