BNUOJ 28892 Flower (二分+网络流)

来源:互联网 发布:张大奕有几个淘宝店 编辑:程序博客网 时间:2024/06/04 00:43

题目链接:http://www.bnuoj.com/v3/problem_show.php?pid=28892

题意:

在空间中给定n个点,给出每个点的三维坐标,以及每个点上已有的花的数目Fi,和可以从该点上移走的花的数目Li,因为每一次可以移动的距离有限,为R, 所以可以选择一个中介点进行转移,最后将所有的花都移动到第一个点上。
因为可以从每个点上移走的花的数目有限,所以,可以通过修改每次可以移动的距离R,  使得最终可以将所有的花移动到第一个点。 求最小的R。 若不存在,这输出-1

分析:

看到求最值的题一般都是dp, 二分, 枚举等等,因为是实数,显然dp, 枚举都行不通的。 所以我们想二分, 假设R一定,就是判断是否可以把所有点的花都能移动到第一个点上; 则我们就可以用最大流可以做了。

构图:

我们每个点i拆成i, 和i+n两个点,连一条边流量为Li,因为每个点最多可以转移Li朵花。汇点很明显就是第一个点。再虚构一个源点, 从源点到点i连一条边, 容量为i点花Fi, 对于任意i和j两点; 如果之间的距离小于R,则在(i+n)和j,(j+n)和i之间各连一条边(想想为什么不是i和(j+n),j和(i+n)),容量为inf; 然后在把每个(i+n)和汇点之间距离小于R的点连一条边,容量为inf。剩下的就是注意精点的问题了。

#include<string.h>#include<vector>#include<queue>#include<algorithm>using namespace std;const int maxn = 500;const int inf = 0x3f3f3f3f;const double eps = 1e-7;struct Edge{    int from, to, cap, flow;    Edge(int i, int j, int c, int f) : from(i), to(j), cap(c), flow(f){}};struct Dinic{    int n, m, s, t;    int d[maxn], cur[maxn];    bool vis[maxn];    vector<int> G[maxn];    vector<Edge> edges;    void inin(int n)    {        this->n = n;        for(int i = 0; i <= n; i++)            G[i].clear();        edges.clear();    }    void AddEdge(int from, int to, int cap)    {        edges.push_back(Edge(from, to, cap, 0));        edges.push_back(Edge(to, from, 0, 0));        m = edges.size();        G[from].push_back(m-2);        G[to].push_back(m-1);    }    bool bfs()    {        memset(d, 0x3f, sizeof(d));        memset(vis, false, sizeof(vis));        queue<int> Q;        d[s] = 0;        Q.push(s);        vis[s] = true;        while(!Q.empty())        {            int u = Q.front();            Q.pop();            for(int i = 0; i < G[u].size(); i++)            {                Edge& e = edges[G[u][i]];                if(!vis[e.to] && e.cap>e.flow)                {                    d[e.to] = d[u] + 1;                    Q.push(e.to);                    vis[e.to] = 1;                }            }        }        return vis[t];    }    int dfs(int x, int a)    {        if(x==t || a==0)            return a;        int f, flow = 0;        for(int& i = cur[x]; i < G[x].size(); i++)        {            Edge& e = edges[G[x][i]];            if(d[e.to]==d[x]+1 && (f=dfs(e.to, min(a, e.cap-e.flow)))>0)            {                e.flow += f;                edges[G[x][i]^1].flow -= f;                flow += f;                a -= f;                if(a == 0)                    break;            }        }        return flow;    }    int max_flow(int s, int t)    {        this->s = s;        this->t = t;        int flow = 0;        while(bfs())        {            memset(cur, 0, sizeof(cur));            flow += dfs(s, inf);        }        return flow;    }};Dinic solve;struct Point{    int x, y, z, f, l;}a[maxn];double d[maxn][maxn];int sum;double dis(Point a, Point b){    double x = (a.x-b.x)*(a.x-b.x)*1.0;    double y = (a.y-b.y)*(a.y-b.y)*1.0;    double z = (a.z-b.z)*(a.z-b.z)*1.0;    return sqrt(x+y+z);}double inint(int n){    memset(d, 0, sizeof(d));    double dd = 0;    sum = 0;    for(int i = 1; i <= n; i++)    {        scanf("%d%d%d%d%d", &a[i].x, &a[i].y, &a[i].z, &a[i].f, &a[i].l);        sum =sum + a[i].f;        for(int j = 1; j < i; j++)        {            d[j][i] = dis(a[j], a[i]);            d[i][j] = d[j][i];            dd = max(dd, d[j][i]);        }    }    sum -= a[1].f;    return dd;}void build(int n, double k){    solve.inin(2*n);    for(int i = 2; i <= n; i++)    {        solve.AddEdge(i, i+n, a[i].l);    }    for(int i = 2; i <= n; i++)    {        for(int j = i+1; j <= n; j++)            if(k-d[i][j]>=-eps)//注意, 不能直接用>= 0            {                solve.AddEdge(i+n, j, inf);                solve.AddEdge(j+n, i, inf);            }    }    for(int i = 2; i <= n; i++)        if(k-d[1][i]>=-eps)            solve.AddEdge(i+n, 1, inf);    for(int i = 2; i <= n; i++)        solve.AddEdge(0, i, a[i].f);}int main(){    int n;    double Max;    while(~scanf("%d", &n))    {        Max = inint(n);        double ans = -1;        double l = 0, r = Max, mid;        while(r-l > eps)        {            mid = (l+r)/2.0;            build(n, mid);            int res = solve.max_flow(0, 1);            if(res == sum)            {                r = mid;                ans = mid;            }            else                l = mid;        }        if(ans < 0)            puts("-1");        else            printf("%.7lf\n", ans);    }    return 0;}





0 0
原创粉丝点击