ZOJ Flower (二分+网络流sap 算法)

ZOJ Problem Set - 3691
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 to point 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, Xi, Yi, Zi, Fi and Li. Xi, Yi 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
Author: REN, Qing

Contest: ZOJ Monthly, March 2013



#include <iostream>
#include <cstdio>
#include <queue>
#include <cmath>
#include <cstring>
#include <cstdlib>
using namespace std;

#define N 100010
#define M 800010
#define INF 2000000000
const int maxn=110;
struct point{
	double x,y,z;
	int c0,m0;
	double getdis2(point p){
		return (x-p.x)*(x-p.x)+(y-p.y)*(y-p.y)+(z-p.z)*(z-p.z) ;
	}
}p[maxn];

struct edge{
    int u,v,next,cap;
}e[M];
int n,head[N],tol,top,st[N];
int src,des,dep[N],gap[N];
int nn,sum;

void initial(){
	tol=0;
    memset(head,-1,sizeof head);
}

void addedge(int u,int v,int c){
    e[tol].u=u,e[tol].v=v,e[tol].next=head[u],e[tol].cap=c,head[u]=tol++;
    e[tol].u=v,e[tol].v=u,e[tol].next=head[v],e[tol].cap=0,head[v]=tol++;
}

void build(double x){
	initial();
	addedge(0,des,INF);
	for(int i=1;i<nn;i++) addedge(src,i,p[i].c0);
	for(int i=1;i<nn;i++) addedge(i,i+nn,p[i].m0);
	for(int i=0;i<nn;i++)
	for(int j=i+1;j<nn;j++)
	if(p[i].getdis2(p[j])<=x*x){
		addedge(i+nn,j,INF);
		addedge(j+nn,i,INF);
	}
}

void bfs(){//对于反边计算层次
    for(int i=0;i<N;i++) dep[i]=N-1;
    memset(gap,0,sizeof gap);
    gap[0]=1,dep[des]=0;
    int q[N],l=0,r=0,u,v;
    q[r++]=des;
    while(l!=r){
        u=q[l++];
        l=l%N;
        for(int i=head[u];i!=-1;i=e[i].next){
            v=e[i].v;
            if(e[i].cap!=0||dep[v]!=N-1) continue;
            q[r++]=v;
            r=r%N;
            ++gap[dep[v]=dep[u]+1];
        }
    }
}

int sap(){
    bfs();
    int u=src,s[N],top=0,res=0,ii;
    int cur[N];
    memcpy(cur,head,sizeof head);
    while(dep[src]<n){
        if(u==des){//求得一条增广路
           int minf=INF,pos=n;
           for(int i=0;i<top;i++){
              if(minf>e[s[i]].cap){
                  minf=e[s[i]].cap;
                  pos=i;
              }
           }
           for(int i=0;i<top;i++){
              e[s[i]].cap-=minf;
              e[s[i]^1].cap+=minf;
           }
           top=pos;
           res+=minf;
           u=e[s[top]].u;//优化1
        }
        if(dep[u]!=0&&gap[dep[u]-1]==0) break;//出现断层
        ii=-1;
        for(int i=cur[u];i!=-1;i=e[i].next){
             if(dep[e[i].v]==N-1) continue;
             if(e[i].cap!=0&&dep[u]==dep[e[i].v]+1){ii=i;break;}
        }
        if(ii!=-1){//有允许弧
            cur[u]=ii;
            s[top++]=ii;
            u=e[ii].v;
        }else{//不断回退找增光路
            int mind=n;
            for(int i=head[u];i!=-1;i=e[i].next){
                if(e[i].cap==0) continue;
                if(dep[e[i].v]<mind) mind=dep[e[i].v],cur[u]=i;
            }
            --gap[dep[u]];
            ++gap[dep[u]=mind+1];//优化2
            if(u!=src) u=e[s[--top]].u;
        }
    }
    return res;
}

void input(){
	src=2*nn,des=nn,sum=0;
	scanf("%lf%lf%lf%d%d",&p[0].x,&p[0].y,&p[0].z,&p[0].c0,&p[0].m0);
	for(int i=1;i<nn;i++){
		scanf("%lf%lf%lf%d%d",&p[i].x,&p[i].y,&p[i].z,&p[i].c0,&p[i].m0);
		sum+=p[i].c0;
	}
	n=2*nn+1;
}

bool can(double x){
	build(x);
	int maxf=sap();
	if(maxf>=sum) return true;
	else return false;
}

void computing(){
	double l=0,r=20000*sqrt(3*1.0);
	while(r-l>1e-7){
		double mid=(l+r)/2;
		if(can(mid)) r=mid;
		else l=mid;
	}
	if(can(r)) printf("%.7lf\n",r);
	else printf("-1\n");
}

int main(){
	while(scanf("%d",&nn)!=EOF){
		input();
		computing();
	}
	return 0;
}


转载于:https://www.cnblogs.com/toyking/p/3797412.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值