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;
}


posted @ 2013-11-01 20:53  炒饭君  阅读(156)  评论(0编辑  收藏  举报