• zoj3691 Flower


    题意:在空间中给定n个点,给出每个点的三维坐标,以及每个点上已有的花的数目Fi,和可以从该点上移走的花的数目Li,因为每一次可以移动的距离有限,为R, 所以可以选择一个中介点进行转移,最后将所有的花都移动到第一个点上。
    因为可以从每个点上移走的花的数目有限,所以,可以通过修改每次可以移动的距离R,  使得最终可以将所有的花移动到第一个点。 求最小的R。 若不存在,这输出-1
    分析:求最小的R, 我们可以二分,转化为判定性问题。 如果已知R, 问是否能将所有的花移动到第一个点呢? 问题是否好解决一点了?? 将所有的花移动到第一个点,其实就是一个很明显的网络流判是否满流的问题了。
    问题就是构图了。
    虚拟一个源点,汇点就比较明显了,就是第一个点。
    首先是拆点,将每一个点拆成一个 i点和 一个i +n, 连边,容量为Li,, 这是容量限制,表示经过该i点最多能有Li朵花(根据题目要求)
    接着,根据R的距离,将可以转移的点连边, (注意是无向边,而且点已经拆成入点跟出点了,),容量为INF, 无穷大
    再来是汇点,将所以与第一个点满足距离要求的点连边,容量也为INF
    从源点往所有点连一条边,容量为Fi, 最后判断是否满流
    zoj3691
    #include<iostream>
    #include<algorithm>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    
    using namespace std;
    
    const int N = 210;
    const int M = 80010;
    const double eps = 1e-7;
    const int INF = 100000000;
    
    int size,head[N],dis[N],gap[N],pre[N],cur[N];
    
    struct edge
    {
        int v,w,next;
        edge(){}
        edge(int v,int next,int w=0):v(v),next(next),w(w){}
    }E[M];
    
    
    inline void insert(int u,int v,int w)
    {
        E[size]=edge(v,head[u],w);
        head[u]=size++;
        E[size]=edge(u,head[v],0);
        head[v]=size++;
    }
    
    int ISAP(int src,int des, int n)
    {
        int maxflow=0;
        memset(dis,0,sizeof(dis));
        memset(gap,0,sizeof(gap));
        for(int i=0;i<=n;i++)
            cur[i]=head[i];
        int u=pre[src]=src;
        int aug=-1;
        while(dis[src]<n)
        {
    loop:    for(int &i=cur[u];i!=-1;i=E[i].next)
            {
                int v=E[i].v;
                if(E[i].w && dis[u]==dis[v]+1)
                {
                    aug=min(aug,E[i].w);
                    pre[v]=u;
                    u=v;
                    if(v==des){
                        maxflow+=aug;
                        for(u=pre[u];v!=src;v=u,u=pre[u])
                        {
                            E[cur[u]].w-=aug;
                            E[cur[u]^1].w+=aug;
                        }
                        aug=INF;
                    }
                    goto loop;
                }
            }
            int mdis=n;
            for(int i=head[u];i!=-1;i=E[i].next)
            {
                int v=E[i].v;
                if(E[i].w && mdis>dis[v])
                {
                    cur[u]=i;
                    mdis=dis[v];
                }
            }
            if((--gap[dis[u]])==0)
                break;
            gap[dis[u]=mdis+1]++;
            u=pre[u];
        }
        return maxflow;
    }
    
    void init()
    {
        memset(head,-1,sizeof(head));
        size=0;
    }
    
    int F[N], L[N], x[N], y[N], z[N];
    double dist[N][N];
    
    inline double getDist(int x1, int y1, int z1, int x2, int y2, int z2)
    {
        return sqrt(double((x1 - x2) * 1ll * (x1 - x2) + (y1 - y2) * 1ll * (y1 - y2) + (z1 - z2) * 1ll * (z1 - z2)));
    }
    
    void init_Dist(int n)
    {
        for(int i = 1; i <= n; ++i)
            for(int j = i + 1; j <= n; ++j)
            {
                dist[i][j] = getDist(x[i], y[i], z[i], x[j], y[j], z[j]);
                dist[j][i] = dist[i][j];
            }
    }
    
    void build(double mid, int n)
    {
        for(int i = 2; i <= n; ++i)//拆点, 限容
            insert(i, i + n, L[i]);
        for(int i = 2; i <= n; ++i)//连边
            for(int j = i + 1; j <= n; ++j)
                if(dist[i][j] <= mid)
                {
                    insert(i + n, j, INF);
                    insert(j + n, i, INF);
                }
        for(int i = 2; i <= n; ++i)//汇点
        {
            if(dist[1][i] <= mid)
                insert(i + n, 1, INF);
        }
        for(int i = 2; i <= n; ++i)//源点
            insert(2 * n + 1, i, F[i]);
    }
    int main()
    {
        int n;
        while(scanf("%d",&n) == 1)
        {
            bool flag = true;
            int tot = 0;
            for(int i = 1; i <= n; ++i)
            {
                scanf("%d %d %d %d %d", &x[i], &y[i], &z[i], &F[i], &L[i]);
                tot += F[i];
            }
            tot -= F[1];
    
            init_Dist(n);
            double left = 0, right = 50000.0;
            double ans = -1;
            while(right - left > eps)//二分枚举答案
            {
                double mid = (left + right) / 2.0;
                init();
                build(mid, n);
                int tmp = ISAP(2 * n + 1, 1, 2 * n + 1);
                if(tmp == tot)
                {
                    ans = mid;
                    right = mid;
                }
                else left = mid;
            }
            if(ans < 0) puts("-1");
            else printf("%.7f\n",ans);
    
        }
        return 0;
    }
  • 相关阅读:
    2019 SDN上机第2次作业
    2019 SDN上机第1次作业
    第07组 团队Git现场编程实战
    第二次结对编程作业
    c语言之问题集
    2019春第2次课程设计实验安排
    2019年十二周总结
    第十一周总结
    第十周作业
    第九周总结
  • 原文地址:https://www.cnblogs.com/nanke/p/2997709.html
Copyright © 2020-2023  润新知