您的位置:首页 > 其它

ZOJ 3691 Flower

2013-04-02 19:13 309 查看
/*

题目: Flower
题目连接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4974
题目大意:

   三维空间中有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。

解题思路:

遇到此类型的题,第一个感觉就是二分R,因为这里的R是单调的(因为小R符合,大R肯定符合,所以是单调的)现在问题在于怎么
判定R的合法性,通过对题目的分析,每个点有一个L[i],F[i]值,且L[i]值决定了最大流出量,而我们最后是要把所有的花都转移到1号点
那么2-n号点的总F[i]值决定了总流量,现在的判定就变成了在已知所有点的最大流出量能不能使最后流到1号点的总流量等于sum{F[i]}(1<i<=n)
的问题,这就是一个最大流模型了,当遇到点有流量时,我们最常见的做法就是拆点,把i点拆成i,i+n点,并在i点和i+n之间建一条边,边的流量
值等于i点流量值,流进i的流量还是流进i点,而从i点流出的流量拆点后变成了从i+n点流出,因为在这个图中还缺一个源点,我们增加一个源点0,

0点流向2-n号点,且流向每个点的流量为F[i],最后原问题就变成了判定从0点到1点的最大流和sum{F[i]}(1<i<=n)是否相等,如果相等表示此R是可以的,

否则此R是不合法的,就这样一直二分R下去,如果二分到最后R的值大于所有两点之间的距离,那么此题无解。

 如果对网络流不熟悉的同学,请先看看网络流的相关资料,比如dinic算法,gap优化等方面(刘汝佳老师的白书上就有)。
*/

#include<math.h>
#include<stdio.h>
#include<string.h>
#include<queue>

using namespace std;

#define inf 2000000000

struct node
{
double x,y,z;
}point[110];

double dis(node a,node 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));
}

int F[110],L[110];

double mp[110][110],Max;
void init(int n)
{
int i,j;Max=0;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
mp[i][j]=dis(point[i],point[j]);
if(mp[i][j]>Max)
Max=mp[i][j];
}
}

#define N 300
#define M 100000

struct edge
{
int from,to,c,next;
}edge[M];
int ant,head
,dep
,gap
;
void add(int a,int b,int c)
{
edge[ant].from=a;
edge[ant].to=b;
edge[ant].c=c;
edge[ant].next=head[a];
head[a]=ant++;
edge[ant].from=b;
edge[ant].to=a;
edge[ant].c=0;
edge[ant].next=head[b];
head[b]=ant++;
}

void BFS(int start,int end)
{
int i,to,u;
memset(dep,-1,sizeof(dep));
memset(gap,0,sizeof(gap));
queue < int > que ;
dep[end]=0;
gap[0]=1;
que.push(end);
while(!que.empty())
{
u=que.front();
que.pop();
for(i=head[u];i!=-1;i=edge[i].next)
{
to=edge[i].to;
if(dep[to]!=-1||edge[i].c!=0)continue;
que.push(to);
dep[to]=dep[u]+1;
++gap[dep[to]];
}
}
}

int s
,cur
;
int Gap(int start,int end,int n)
{
int res=0;
BFS(start,end);
int u=start,top=0;
memcpy(cur,head,sizeof(head));
while(dep[start]<n)
{
int i;
if(u==end)
{
double Min=inf;
int flag;
for(i=0;i<top;i++)
{
if(edge[s[i]].c<Min)
{
Min=edge[s[i]].c;
flag=i;
}
}
res+=Min;
for(i=0;i<top;i++)
{
edge[s[i]].c-=Min;
edge[s[i]^1].c+=Min;
}
top=flag;
u=edge[s[top]].from;
}
if(u!=end&&gap[dep[u]-1]==0)break;
for(i=cur[u];i!=-1;i=edge[i].next)
{
if(edge[i].c!=0&&dep[edge[i].to]+1==dep[u])
break;
}
if(i!=-1)
{
cur[u]=i;
s[top++]=i;
u=edge[i].to;
}
else
{
int Min=n;
for(i=head[u];i!=-1;i=edge[i].next)
{
if(edge[i].c==0)continue;
if(Min>dep[edge[i].to])
{
cur[u]=i;
Min=dep[edge[i].to];
}
}
--gap[dep[u]];
dep[u]=Min+1;
++gap[dep[u]];
if(u!=start)
u=edge[s[--top]].from;
}
}
return res;
}

int judge(double width,int n)
{
int i,j;
int maxf=0; ant=0;
memset(head,-1,sizeof(head));
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
{
if(mp[i][j]<=width)
{
add(i+n,j,inf);
add(j+n,i,inf);
}
}
add(i,i+n,L[i]);
if(i>1){
add(0,i,F[i]);
maxf+=F[i];
}
}
return Gap(0,1,2*n+1)==maxf;
}

int main()
{
int n,i;
double l,r,mid;
while(scanf("%d",&n)!=EOF)
{
for(i=1;i<=n;i++)
{
scanf("%lf%lf%lf%d%d",&point[i].x,&point[i].y,&point[i].z,&F[i],&L[i]);
}
init(n);
r=1e20,l=0;
while(r-l>0.00000001)
{
mid=(l+r)/2;
if(judge(mid,n))
r=mid;
else
l=mid;
}
if(mid>Max) printf("-1\n");
else printf("%.7lf\n",mid);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: