zoukankan      html  css  js  c++  java
  • zoj 2874 & poj 3308 Paratroopers (最小割)

    意甲冠军:
    一m*n该网络的规模格。详细地点称为伞兵着陆(行和列)。

    现在,在一排(或列)
    安装激光枪,激光枪可以杀死线(或塔)所有伞兵。在第一i安装一排
    费用是Ri。在第i列安装的费用是Ci。

    要安装整个激光枪系统,总费用为这些
    激光枪费用的乘积。
    求杀死全部伞兵的最小费用。



    构图:
    把伞兵视为边,行与列视为顶点。添加源点和汇点,对于第i行。从源点向顶点i连接一条
    容量为Ri的边。对于第j列。从顶点j向汇点连接一条容量为Rj的边。
    假设某一点(i,j)有伞兵降落,则从顶点Ri向顶点Cj连接一条容量为无穷大的边。


    算法:
    依据割的性质,源点和汇点必不连通。则割边必然在S->R,R->C,C->T其一。

    为了求得最小容量,
    将R->C设为无穷大,则其不可能被选中。这样割边集为S-->R,C-->T的集合,也就是选中行或列。
    此时求得的最小割为花费最小的方案。


    因为花费为行和列的乘积。则通过对数运算把乘法转化为加法。


    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #define maxm 15000
    #define maxn 105
    #define eps 1e-6
    using namespace std;
    
    struct node
    {
        int v,next;
        double val;
    }e[maxm<<1];
    int st,en,n,m,l,cnt;
    int d[maxn];
    int head[maxn],cur[maxn];
    const double INF = 1000007;
    queue<int> q;
    
    void init()
    {
        st = 0,en = n+m+1;
        memset(head,-1,sizeof(head));
        cnt = 0;
    }
    void add(int x,int y,double z)
    {
        e[cnt].v = y;
        e[cnt].val = z;
        e[cnt].next = head[x];
        head[x]=cnt++;
        e[cnt].v = x;
        e[cnt].val = 0;
        e[cnt].next = head[y];
        head[y]=cnt++;
    }
    bool bfs()
    {
        while(!q.empty())
            q.pop();
        memset(d,-1,sizeof(d));
        int u;
        d[st] = 0;
        q.push(st);
        while(!q.empty())
        {
            u = q.front();
            q.pop();
            for(int i=head[u];i!=-1;i=e[i].next)
            {
                int t = e[i].v;
                if(e[i].val>0 && d[t]==-1)
                {
                    d[t] = d[u]+1;
                    q.push(t);
                    if(t==en) return true;
                }
            }
        }
        return false;
    }
    
    double dfs(int x,double flow)
    {
        if(x==en || fabs(flow)<=eps) return flow;
        double ret = 0,dd;
        for(int& i=cur[x];i!=-1;i=e[i].next)
        {
            int t = e[i].v;
            if(d[t] == d[x]+1 && (dd = dfs(t,min(flow,e[i].val)))>0)
            {
                e[i].val-=dd;
                e[i^1].val+=dd;
                flow-=dd;
                ret+=dd;
                if (fabs(flow) <= eps) break;
            }
        }
        return ret;
    }
    double Dinic()
    {
        double tmp = 0,maxflow = 0;
        while(bfs())
        {
            for(int i=0;i<=en;i++)
                cur[i] = head[i];
            maxflow+=dfs(st,INF);
        }
        return maxflow;
    }
    
    int main()
    {
        int T,a,b;
        double x;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d%d",&m,&n,&l);
            init();
            for(int i=1;i<=m;i++)
            {
                scanf("%lf",&x);
                add(st,i,log(x));
            }
            for(int i=1;i<=n;i++)
            {
                scanf("%lf",&x);
                add(i+m,en,log(x));
            }
            for(int i=1;i<=l;i++)
            {
                scanf("%d%d",&a,&b);
                add(a,b+m,INF);
            }
            printf("%.4f
    ",exp(Dinic()));
        }
        return 0;
    }
    



    版权声明:本文博主原创文章。博客,未经同意不得转载。

  • 相关阅读:
    为什么我要学习qt quick
    geometory Intersect
    删除kubernetes节点的正确姿势
    乞丐版docker私有仓库搭建
    kubernetes集群中由于某些原因导致etcd节点没有删干净,需要手动清理etcd节点
    k8s coredns设置上游name server
    虚拟机架设koolshare软路由
    文件类型特征码
    深入字节码 -- 计算方法执行时间
    启迪思维:二叉树
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4906142.html
Copyright © 2011-2022 走看看