zoukankan      html  css  js  c++  java
  • POJ

    题意:N*M个格点,K个位置会有敌人.每行每列都有一门炮,能打掉这一行(列)上所有的敌人.每门炮都有其使用价值.总花费是所有使用炮的权值的乘积.求最小的总花费.

    若每门炮的权值都是1,就是求最小点覆盖的问题,参考:http://poj.org/problem?id=3041

    将行视作X部,列视作Y部,敌人(i,j)视作连接点i和点N+j的边,要求一个点集合,使其能覆盖所有的边,且权值之积最小,即求最小点权覆盖.与求最大权独立集一样,也是用网络流求解.
    这里处理积的方法是,将权值取对数,则log(a*b) = log(a) + log(b),转化为了加法运算.
    建图步骤:建立源点s与汇点t.从源点s向X部的点建边,从Y部的点向汇点t建边,容量为其权值取对数.对敌人(i,j),由i向j+N建容量为正无穷的边.
    跑出最大流即为其最小点权覆盖的值,最后pow计算出实际花费.

    *其实带权的二分图,用网络流求最小点权覆盖与求最大独立集还是运用了二分图中的思想.二分图中,|最大独立集| = N - |最小点权覆盖| = N - |最大匹配|.
    而在用网络流求解时,|最大流| = |最小割| = |最小点权覆盖|, |最大权独立集| = |总权值| - |最小点权覆盖| = |总权置| - |最大流|

    #include<iostream>
    #include<cstring>
    #include<stdio.h>
    #include<algorithm>
    #include<string>
    #include<cmath>
    using namespace std;
    const double INF = 100000.0;
    const int MAXN=3010;//点数的最大值
    const int MAXM=400010;//边数的最大值
    #define captype double
    
    struct SAP_MaxFlow{
        struct Edge{
            int from,to,next;
            captype cap;
        }edges[MAXM];
        int tot,head[MAXN];
        int gap[MAXN];
        int dis[MAXN];
        int cur[MAXN];
        int pre[MAXN];
    
        void init(){
            tot=0;
            memset(head,-1,sizeof(head));
        }
        void AddEdge(int u,int v,captype c,captype rc=0){
            edges[tot] = (Edge){u,v,head[u],c};  head[u]=tot++;
            edges[tot] = (Edge){v,u,head[v],rc}; head[v]=tot++;
        }
        captype maxFlow_sap(int sNode,int eNode, int n){//n是包括源点和汇点的总点个数,这个一定要注意
            memset(gap,0,sizeof(gap));
            memset(dis,0,sizeof(dis));
            memcpy(cur,head,sizeof(head));
            pre[sNode] = -1;
            gap[0]=n;
            captype ans=0;
            int u=sNode;
            while(dis[sNode]<n){
                if(u==eNode){
                    captype Min=INF ;
                    int inser;
                    for(int i=pre[u]; i!=-1; i=pre[edges[i^1].to])
                    if(Min>edges[i].cap){
                        Min=edges[i].cap;
                        inser=i;
                    }
                    for(int i=pre[u]; i!=-1; i=pre[edges[i^1].to]){
                        edges[i].cap-=Min;
                        edges[i^1].cap+=Min;
                    }
                    ans+=Min;
                    u=edges[inser^1].to;
                    continue;
                }
                bool flag = false;
                int v;
                for(int i=cur[u]; i!=-1; i=edges[i].next){
                    v=edges[i].to;
                    if(edges[i].cap>0 && dis[u]==dis[v]+1){
                        flag=true;
                        cur[u]=pre[v]=i;
                        break;
                    }
                }
                if(flag){
                    u=v;
                    continue;
                }
                int Mind= n;
                for(int i=head[u]; i!=-1; i=edges[i].next)
                if(edges[i].cap>0 && Mind>dis[edges[i].to]){
                    Mind=dis[edges[i].to];
                    cur[u]=i;
                }
                gap[dis[u]]--;
                if(gap[dis[u]]==0) return ans;
                dis[u]=Mind+1;
                gap[dis[u]]++;
                if(u!=sNode) u=edges[pre[u]^1].to;  //退一条边
            }
            return ans;
        }
    }F;
    
    int main()
    {
    	#ifndef ONLINE_JUDGE
            freopen("in.txt","r",stdin);
            freopen("out.txt","w",stdout);
        #endif
        int T; scanf("%d", &T);
        double cap;
        int u,v,tmp;
        while(T--){
            F.init();
            int n,m,k; scanf("%d %d %d",&n, &m,&k);
            int s = 0, t  = n+m+1;
            for(int i=1;i<=n;++i){
                scanf("%lf", &cap);
                F.AddEdge(s,i,log(cap));
            }
            for(int i=1;i<=m;++i){
                scanf("%lf", &cap);
                F.AddEdge(i+n,t,log(cap));
            }
            while(k--){
                scanf("%d %d",&u,&v);
                F.AddEdge(u,v+n,INF);
            }
            double res = exp(F.maxFlow_sap(s,t,t+1));
            printf("%.4lf
    ",res);
        }
        return 0;
    }
    
    
    为了更好的明天
  • 相关阅读:
    工业相机基础知识
    软件测试最常用的 SQL 命令 | 掌握基本查询、条件查询、聚合查询
    一文掌握软件测试常用SQL命令
    PageObject设计模式在 UI 自动化中的实践(QQ 邮箱登陆为例)
    测试开发必备--搞定PO设计模式
    Junit5 + YAML 参数化和数据驱动,让 App 自动化测试更高效(一)
    快速搞定APP移动端自动化测试
    接口自动化测试的 “能” 与 “不能”
    如何精通接口测试?
    测试开发必备:Dubbo-admin+Zookeeper 的环境搭建实操
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9683269.html
Copyright © 2011-2022 走看看