ZOJ 3691 Flower

题意: 给出n个点。每个点有Fi朵花,和限制Li(总共能从i点移出Li朵花),同时给出点坐标(Xi,Yi,Zi)。问:能不能把所有点的花都移到第一个点?如果能,求出最小需求R(R是两点之间移动距离的限制,如果距离超出R,则此点的花就无法移动到那点)。


思路:很裸的网络流,拆点建图。i作为入点,i'作为出点,i和i'直接连一条容量为Li的边,距离为0。然后图中任意两点求出距离,连起来,容量为无穷。最后所有点连一个源点,容量为Fi,距离0,第一个点连一个汇点,容量为∑Fi。 建好图后二分答案即可。


代码:

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<math.h>
#include<set>
#include<list>
#include<map>
#include<vector>
#include<string.h>
#include<queue>
using namespace std;

#define ll  long long
#define N 220
#define sq(x) ((x)*(x))
const int INF=0xfffffff;

int n;

struct node{
	int x,y,z,f,l;
}a[N];

int p[N],eid;

struct edge{
	int vid,next,vol,init;
	double cost;
}e[(N*N)<<1];

void init()
{
	eid=0;
	memset(p,-1,sizeof(p));
}

void insert(int from,int to,int vol,double cost)
{
	e[eid].vid=to;
	e[eid].init=vol;
	e[eid].cost=cost;
	e[eid].next=p[from];
	p[from]=eid++;
	swap(from,to);
	e[eid].vid=to;
	e[eid].init=0;
	e[eid].cost=cost;
	e[eid].next=p[from];
	p[from]=eid++;
}

int s,t;
int gap[N],h[N];
int dfs(int u,int curFlow,int n,double maxd)
{
	int v,resFlow=curFlow,minFlow,minh=n-1;
	if(u==t) return curFlow;
	for(int i=p[u];i!=-1;i=e[i].next){
		v=e[i].vid;
		if(e[i].vol>0 && e[i].cost<=maxd){
			if(h[u]==h[v]+1){
				minFlow=min(resFlow,e[i].vol);
				minFlow=dfs(v,minFlow,n,maxd);
				e[i].vol-=minFlow;
				e[i^1].vol+=minFlow;
				resFlow-=minFlow;
				if(h[s]>=n) return curFlow-resFlow;
				if(resFlow==0) break;
			}
			if(h[v]<minh) minh=h[v];
		}
	}
	if(resFlow==curFlow){
		gap[h[u]]--;
		if(gap[h[u]]==0) h[s]=n;
		h[u]=minh+1;
		gap[h[u]]++;
	}
	return curFlow-resFlow;
}

bool ISAP(int n,int needFlow,double maxd)
{
	int maxFlow=0;
	memset(gap,0,sizeof(gap));
	memset(h,0,sizeof(h));
	gap[0]=n;
	for(int i=0;i<eid;i++)
		e[i].vol=e[i].init;
	while(h[s]<n)
		maxFlow+=dfs(s,INF,n,maxd);
	return maxFlow==needFlow;
}

double solve(int needFlow)
{
	double l=0,r=1e7,mid,e=1e-7;
	while(l+e<r){
		mid=(l+r)/2;
		if(!ISAP(2*n+2,needFlow,mid)){
			l=mid+1e-7;
		}else{
			r=mid;
		}
	}
	if(r==1e7) return -1;
	else return r;
}

void makeMap(int sum)
{
	double d;
	init();
	s=0;t=n+n+1;
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			d=sqrt(0.0+sq(a[i].x-a[j].x)+sq(a[i].y-a[j].y)+sq(a[i].z-a[j].z));
			insert(i+n,j,INF,d);
			insert(j+n,i,INF,d);
		}
	}
	for(int i=1;i<=n;i++){
		insert(s,i,a[i].f,0);
		insert(i,i+n,a[i].l,0);
	}
	insert(1,t,sum,0);
}

int main()
{
	int sum;
	while(scanf("%d",&n)!=EOF){
		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+=a[i].f;
		}
		makeMap(sum);		
		double ans=solve(sum);
		if(ans!=-1)
			printf("%.7f\n",ans);
		else puts("-1");
	}
	return 0;
}


你可能感兴趣的:(ZOJ,2013,monthly,march)