太空飞行计划问题(最大流,经典最大权闭合子图问题)

简介: 太空飞行计划问题(最大流,经典最大权闭合子图问题)

扶苏大佬的解释(最大权闭合子图问题解法)

讲讲怎样保存方案和输出:

一个结论就是假如我们跑的是 Dinic 那么我们最后一次网络流(这一次网络流并没有起任何作用,只是确认了无更多残余流量可以退出了。)中所有被分到层的都一定被选上了。

没有更多残余流量其实意味着这个图已经被割成了两部分,一个实验如果有层数意味着它没有被割掉(被选上了),一个仪器如果有层数意味着它已经被割掉了(也是被选上了)。

于是只要在最后输出所有有层数的点就行了。

我的代码

#include<bits/stdc++.h>
using namespace std;
const int N=30000,INF=0x3f3f3f3f;
int h[N],f[N],ne[N],e[N],idx;
int q[N], d[N], cur[N];//q是队列,d是分成,cur是优化];
int n,m;
int fl=0;
int S,T;
int ans;
inline int read()
{
  int X = 0;
  bool flag = 1;
  char ch = getchar();
  while (ch < '0' || ch > '9')
  {
    if (ch == '-') flag = 0;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') {
    X = (X << 1) + (X << 3) + ch - '0';
    ch = getchar();
  }
  if (ch == '\n') fl = 1;
  if (flag) return X;
  return ~(X - 1);
}
inline void write(int X)
{
  if(X<0) {X=~(X-1); putchar('-');}
  if(X>9) write(X/10);
  putchar(X%10+'0');
}
void add(int a,int b,int c)
{
    f[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
    f[idx]=0,e[idx]=a,ne[idx]=h[b],h[b]=idx++;
}
int bfs()
{
  memset(d, -1, sizeof d);
  int tt = 0, hh = 0;
  q[0] = 0, d[0] = 0, cur[0] = h[0];//当前弧是第一个点
  while (hh <= tt)
  {
    int t = q[hh ++ ];
    for (int i = h[t]; ~i; i = ne[i])
    {
      int ver = e[i];
      if (d[ver] == -1 && f[i])//当前点没有被搜索,且流量大于0
      {
        d[ver] = d[t] + 1;
        cur[ver] = h[ver];
        //当前点的当前弧 
        if (ver == T) return true;
        q[++ tt] = ver;
      }
    }
  }
  return false;
}
int find(int u, int limit )//从原点能够流向u这个点的最大流量为limit
{
  if (u == T) return limit;//如果已经到终点了 表示从原点到终点所能流的流量就是limit
  int flow = 0;//表示从u这个点开始往后流的流量是多少,dfs求,一开始是0的 
  //我们之前可能搜索u,可能有些路径满了,所以要将所有满的路径跳过
  for (int i = cur[u]; ~i && flow < limit; i = ne[i])//如果从u到终点的总流量等于limit就没有必要再搜了,因为起点到u最多就是limit 
  {
    cur[u] = i;//记录一下当前搜的弧是那个,流到第i条边,说明前面的边都流过了
    int ver = e[i];
    if (d[ver] == d[u] + 1 && f[i])//流到下一层,且当前弧可流
    {
      //从当前点开始最多可以有多少流量
      int t = find(ver, min(f[i], limit - flow));
      if (!t) //从这个点到终点没有流量,说明是不可用的,就把这个点删掉
        d[ver] = -1;//这个点到终点没有路径
      f[i] -= t, f[i ^ 1] += t, flow += t;
    }
  }
  return flow;
}
int dinic()
{
  int r = 0, flow;
  //判断如果有增广路并建立出分层图,然后找出所有增广路,将所有流量加起来
  while (bfs()) while (flow = find(S, INF)) r += flow;
  return r;
}
int main()
{
    memset(h,-1,sizeof h);
    m=read(); 
    n=read();
    S=0;
    T=n+m+1;
    for(int i=1;i<=m;i++)
    {
        fl=0;
        int x,y;
        x=read();
        ans+=x;
        add(S,i+n,x);
        while(fl!=1)
        {
            y=read();
            add(i+n,y,INF);
        }
    }
    for(int i=1;i<=n;i++)
    {
         int y=read();
        add(i,T,y);
    }   
    int t=dinic();
    int l=0,r=0;
    for(int i=1;i<=m;i++)
    {
        if(d[i+n]!=-1) l=i+n;
    }
    for(int i=1;i<=n;i++)
    {
            if(d[i]!=-1) r=i;
    }
   for(int i=1;i<=m;i++) {if(d[i+n]!=-1&&l!=i+n){ cout<<i<<" ";}else if(d[i+n]!=-1&&l==i+n)cout<<i<<"\n";} 
    for(int i=1;i<=n;i++){if(d[i]!=-1&&r!=i){ cout<<i<<" ";}else if(d[i]!=-1&&r==i)cout<<i<<"\n";} 
    cout<<ans-t<<'\n';    
}
}
目录
相关文章
|
6月前
有红、白、黑三种球若干个,求红白黑球的数量
有红、白、黑三种球若干个,求红白黑球的数量
58 1
|
6月前
|
人工智能 BI 测试技术
【深度优先搜索】【图论】【树】2646. 最小化旅行的价格总和
【深度优先搜索】【图论】【树】2646. 最小化旅行的价格总和
|
6月前
最大流圆桌问题(二分图多重匹配问题)
最大流圆桌问题(二分图多重匹配问题)
49 0
|
1月前
论多段图的最短路径问题(我认为本质上还是暴力枚举法)
本文讨论了多段图最短路径问题的解决方法,认为本质上是使用暴力枚举法,通过逐步计算每个阶段点的最短距离来确定从起点到终点的最短路径。
35 1
论多段图的最短路径问题(我认为本质上还是暴力枚举法)
|
5月前
|
算法 Python
二维矩形件排样算法之最低水平线搜索算法实现
二维矩形件排样算法之最低水平线搜索算法实现
148 0
|
6月前
|
机器学习/深度学习 算法 测试技术
【单源最短路 图论】882. 细分图中的可到达节点
【单源最短路 图论】882. 细分图中的可到达节点
|
6月前
|
算法 测试技术 C#
【图论】 【割点】 【双连通分类】LCP 54. 夺回据点
【图论】 【割点】 【双连通分类】LCP 54. 夺回据点
|
6月前
6366. 在网格图中访问一个格子的最少时间(dijkstra在矩阵上的运用)
6366. 在网格图中访问一个格子的最少时间(dijkstra在矩阵上的运用)
|
6月前
|
机器学习/深度学习 存储 算法
C# | 凸包算法之Graham,快速找到一组点最外侧的凸多边形
这篇关于凸包算法的文章,本文使用C#和Graham算法来实现凸包算法。 首先消除两个最基本的问题: 什么是凸包呢? 凸包是一个包围一组点的凸多边形。凸多边形是指多边形中的每个内角都小于180度的多边形。 凸包算法有什么用呢? 凸包算法的作用是找到这个凸多边形,并且使用最少的点来绘制出它的轮廓。凸包算法在计算机图形学、计算几何和机器学习等领域中有着广泛的应用。
136 0
|
11月前
|
算法
最优闭回路问题
最优闭回路问题