题意: 给出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;
}
本文介绍了一个关于在三维空间中搬运花卉的问题,并通过网络流算法进行求解。文章详细阐述了如何构建图模型,包括节点和边的设计,以及如何使用ISAP算法进行最大流最小费用的计算。
727

被折叠的 条评论
为什么被折叠?



