• 刷题总结——太空飞行计划(最大权闭合子图用最大流解决)


    题目:

    题目描述

    W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合 E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合 I={I1, I2,…In}。 实验 Ej 需要用到的仪器是 I 的子集 Rj∈I。配置仪器 Ik 的费用为 Ck 美元。实验 Ej 的赞助商已同意为该实验结果支付 Pj 美元。W 教授的任务是找出一个有效算法, 确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。 
    对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划,输出最大收益值。 

    输入格式

    输入文件第 1 行有 2 个正整数 m 和 n(1<=m,n<=400)。其中 m 是实验数,n 是仪器数。接下来的 m 行,每行是一个实验的有关数据(每个数不超过50)。第一个数赞助商同意支付该实验的费用;接着是该实验需要用到的若干仪器的编号。最后一行的 n 个数是配置每个仪器的费用。

    输出格式

    输出一个整数,即最大的净收益值。 

    样例数据 1

    输入  [复制]

     
    2 3 
    10 1 2 
    25 2 3 
    5 6 7

    输出

    17

    题解:

      比较明显可以看出是一个最大权闭合子图(定义参见网上资料)

      这里给出求最大权闭合子图方法:

      建一个网络,s连正点,边权设为所连点点权;负点权向t点连边,边权为所出发点点权绝对值,点与点之间连原图上的边,边权为inf

      可以证明答案为正权和-最大流(最小割)(具体怎么证的看http://www.cnblogs.com/wuyiqi/archive/2012/03/12/2391960.html(引用,%%%%%%))

    代码:

      

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<cctype>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int inf=1e+9;
    const int N=1000;
    int first[N*2],go[N*N],next[N*N],rest[N*N],tot=1,lev[N];
    int m,n,src,des,ans;
    char t;
    inline void comb(int a,int b,int c)
    {
      next[++tot]=first[a],first[a]=tot,go[tot]=b,rest[tot]=c;
      next[++tot]=first[b],first[b]=tot,go[tot]=a,rest[tot]=0;
    }
    inline bool bfs()
    {
      static int que[N*4],tail;
      for(int i=src;i<=des;i++)  lev[i]=-1;
      que[tail=1]=src;
      lev[src]=0;
      for(int head=1;head<=tail;head++)
      {
        int u=que[head];
        for(int e=first[u];e;e=next[e])
        {
          int v=go[e];
          if(rest[e]&&lev[v]==-1)
          {
            lev[v]=lev[u]+1;
            que[++tail]=v;
            if(v==des)
              return true;
          }
        }
      }
      return false;
    }
    inline int dinic(int u,int flow)
    {
      if(u==des)
        return flow;
      int res=0,delta,v;
      for(int e=first[u];e;e=next[e])
      {
        v=go[e];
        if(lev[v]>lev[u]&&rest[e])
        {
          delta=dinic(v,min(rest[e],flow-res));
          if(delta)
          {
            rest[e]-=delta;
            rest[e^1]+=delta;
            res+=delta;
            if(res==flow)  break;
          }  
        }
      }
      if(res!=flow)  lev[u]=-1;
      return res;
    }
    void maxflow()
    {
      while(bfs())
        ans+=dinic(src,inf);
    }
    int main()
    {
      //freopen("a.in","r",stdin);
      scanf("%d%d",&m,&n);
      src=0,des=n+m+1;
      int a,tot=0;
      for(int i=1;i<=m;i++)
      {
        scanf("%d",&a);
        comb(0,i,a);
        tot+=a;
        scanf("%c",&t);
        while(t!='
    ')
        {
          scanf("%d",&a);
          comb(i,m+a,inf);
          scanf("%c",&t);
        }
      }
      for(int i=1;i<=n;i++)
      {
        scanf("%d",&a);
        comb(m+i,des,a);
      }
      maxflow();
      cout<<tot-ans<<endl;
      return 0;
    }
  • 相关阅读:
    不运用正则排除出现的特定数的数字
    重绘 贝赛尔曲线特效
    缓动类gs.TweenLite示例
    画方格(二维数组)
    递归函数
    鼠标经过延时出现Hint
    鼠标控制元件移动带缓动 鼠标点击发射子弹
    A碰到B之后持续加速度的时间问题
    播放完成之后移除动画
    hdu 1032 The 3n + 1 problem (数学)
  • 原文地址:https://www.cnblogs.com/AseanA/p/7462755.html
Copyright © 2020-2023  润新知