zoukankan      html  css  js  c++  java
  • ZOJ 3691 Flower(最大流+二分)

    Flower

    Time Limit: 8 Seconds      Memory Limit: 65536 KB      Special Judge

    Gao and his girlfriend's relationship becomes better and better after they flying balloon last week. Thus, Gao wants to play a simple but evil game with his girlfriend at a late night.

    The game is simple: there is a three-dimensional space, Gao chooses N points to put flowers. For the point i, it has Fi flowers. And his girlfriend has to move all these flowers topoint 1 altogether. As everyone knows, his girlfriend is not strong like Gao, so she can move flowers from one point to another if and only if the Euclidean distance between two points are smaller or equal to R. In another words, she perhaps has to move flowers to the intermediate point for finally moving all flowers to the point one. In order to stay with his girlfriend as much time as possible, he asks his girlfriend, for the point i, that she can only move out no more than Li flowers (including the points as an intermediate point).

    Can you help his poor girlfriend to calculate the minimal R?

    Input

    There are multiple cases.

    For each case, the first line contains an integer N (1 ≤ N ≤ 100), which means there are N points.

    For the next N lines, each line contains five integers, XiYiZiFi and LiXiYi and Zi are the coordinate of point i (0 ≤ Xi, Yi, Zi ≤ 20000), Fi means there are Fi flowers at the beginning. Li means this point can be moved out no more than Li flowers.

    Output

    For each test case, it contains one real number indicating the minimal R. The results should be rounded to seven decimal places. If there is no solution for this case, please output -1. Output's absolute error less than 1e-6 will be accepted.

    Sample Input

    2
    1 1 1 1 1
    2 2 2 2 2
    

    Sample Output

    1.7320508
    

    题意:三维空间中有n个点。序号为1-n。每一个点有一个坐标。每一个点上有F[i]朵花,每一个点仅仅同意L[i]朵花从这个点转移出到
    别的点,如今Gao的女朋友要把序号2-n点上的花所有转移到1号点上。一个点上的花要转移到1号点上能够经过别的点中转,

    但要符合L[i]的限制,可是Gao的女朋友一次能走的距离是R,假设Gao的女朋友把i号点花转移到j号点上。Gao的女朋友须要

    行走的距离是dis(i,j)。如今问:Gao的女朋友要完毕这项任务须要的最小R,假设完毕不了输出-1。


    题解:二分答案,建图跑最大流,推断是否满流。


    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #define ll long long
    using namespace std;
    
    const int MAXN = 410;//点数的最大值
    const int MAXM = 80010;//边数的最大值
    const int INF = 0x3f3f3f3f;
    
    struct Edge {
        int to,next,cap,flow;
    } edge[MAXM]; 
    int tol,n,m,sum;
    int head[MAXN];
    int gap[MAXN],dep[MAXN],cur[MAXN];
    
    struct Point {
        double x,y,z;
        int f,l;
    } a[MAXN];
    
    double d[MAXN][MAXN];
    
    void init() {
        tol = 0;
        memset(head,-1,sizeof(head));
    }
    
    double dis(Point a,Point b) {
        return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
    }
    
    void addedge(int u,int v,int w,int rw = 0) {
        edge[tol].to = v;
        edge[tol].cap = w;
        edge[tol].flow = 0;
        edge[tol].next = head[u];
        head[u] = tol++;
        edge[tol].to = u;
        edge[tol].cap = rw;
        edge[tol].flow = 0;
        edge[tol].next = head[v];
        head[v] = tol++;
    }
    
    int Q[MAXN];
    
    void BFS(int start,int end) {
        memset(dep,-1,sizeof(dep));
        memset(gap,0,sizeof(gap));
        gap[0] = 1;
        int front = 0, rear = 0;
        dep[end] = 0;
        Q[rear++] = end;
        while(front != rear) {
            int u = Q[front++];
            for(int i = head[u]; i != -1; i = edge[i].next) {
                int v = edge[i].to;
                if(dep[v] != -1)continue;
                Q[rear++] = v;
                dep[v] = dep[u] + 1;
                gap[dep[v]]++;
            }
        }
    }
    
    int S[MAXN];
    
    int sap(int start,int end,int N) {
        BFS(start,end);
        memcpy(cur,head,sizeof(head));
        int top = 0;
        int u = start;
        int ans = 0;
        while(dep[start] < N) {
            if(u == end) {
                int Min = INF;
                int inser;
                for(int i = 0; i < top; i++)
                    if(Min > edge[S[i]].cap - edge[S[i]].flow) {
                        Min = edge[S[i]].cap - edge[S[i]].flow;
                        inser = i;
                    }
                for(int i = 0; i < top; i++) {
                    edge[S[i]].flow += Min;
                    edge[S[i]^1].flow -= Min;
                }
                ans += Min;
                top = inser;
                u = edge[S[top]^1].to;
                continue;
            }
            bool flag = false;
            int v;
            for(int i = cur[u]; i != -1; i = edge[i].next) {
                v = edge[i].to;
                if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u]) {
                    flag = true;
                    cur[u] = i;
                    break;
                }
            }
            if(flag) {
                S[top++] = cur[u];
                u = v;
                continue;
            }
            int Min = N;
            for(int i = head[u]; i != -1; i = edge[i].next)
                if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) {
                    Min = dep[edge[i].to];
                    cur[u] = i;
                }
            gap[dep[u]]--;
            if(!gap[dep[u]])return ans;
            dep[u] = Min + 1;
            gap[dep[u]]++;
            if(u != start)u = edge[S[--top]^1].to;
        }
        return ans;
    }
    
    bool slove(double R) {
        init();
        int s=0,t=1;
        for(int i=2; i<=n; i++) {
            addedge(i,i+n,a[i].l);
            addedge(s,i,a[i].f);
        }
        for(int i=2; i<=n; i++) {
            for(int j=i+1; j<=n; j++) {
                if(d[i][j]<=R) {
                    addedge(i+n,j,INF);
                    addedge(j+n,i,INF);
                }
            }
            if(d[i][1]<=R)addedge(i+n,1,INF);
        }
        return sum==sap(s,t,2*n);
    }
    
    int main() {
        //freopen("test.in","r",stdin);
        while(cin>>n) {
            sum=0;
            for(int i=1; i<=n; i++) {
                scanf("%lf%lf%lf%d%d",&a[i].x,&a[i].y,&a[i].z,&a[i].f,&a[i].l);
                sum+=a[i].f;
            }
            sum-=a[1].f;
            double MaxD=0;
            for(int i=1; i<=n; i++) {
                for(int j=i+1; j<=n; j++) {
                    d[i][j]=d[j][i]=dis(a[i],a[j]);
                    MaxD=max(MaxD,d[i][j]);
                }
            }
            int flag=0;
            double l=0.0,r=MaxD;
            for(int i=0; i<100; i++) {
                double mid=(l+r)/2;
                if(slove(mid)) {
                    r=mid;
                    flag=1;
                } else  l=mid;
            }
            if(flag)
                printf("%.7f
    ",l);
            else
                printf("-1
    ");
        }
        return 0;
    }
    



  • 相关阅读:
    面向切面编程AOP——加锁、cache、logging、trace、同步等这些较通用的操作,如果都写一个类,则每个用到这些功能的类使用多继承非常难看,AOP就是解决这个问题的,python AOP就是装饰器
    主机异常流量示例
    python代码安全扫描工具
    联邦学习
    数据库索引数据结构总结——ART树就是前缀树
    路由器安全——破解wifi密码,同时中间人攻击
    机器学习(四)--- 从gbdt到xgboost
    Visual Studio 2013新建工程导入现有代码文件夹并且保持目录结构
    腾讯发展重心不再是微信
    linux gz 解压缩
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/7145092.html
Copyright © 2011-2022 走看看