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

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

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

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

一个结论就是假如我们跑的是 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';    
}
}
目录
相关文章
|
4月前
最大流圆桌问题(二分图多重匹配问题)
最大流圆桌问题(二分图多重匹配问题)
29 0
|
4月前
没有给出二分图两个左右点集时的二分图最大匹配
没有给出二分图两个左右点集时的二分图最大匹配
12 0
|
5月前
【每日一题Day243】LC1595连通两组点的最小成本 | 状态压缩dp
【每日一题Day243】LC1595连通两组点的最小成本 | 状态压缩dp
29 0
|
4月前
|
算法
飞行员配对方案(Dinic求最大二分图匹配(对匈牙利算法的优化),以及二分图的建图方式)
飞行员配对方案(Dinic求最大二分图匹配(对匈牙利算法的优化),以及二分图的建图方式)
38 0
|
4天前
|
机器学习/深度学习 算法 测试技术
【单源最短路 图论】3112. 访问消失节点的最少时间
【单源最短路 图论】3112. 访问消失节点的最少时间
|
11天前
6366. 在网格图中访问一个格子的最少时间(dijkstra在矩阵上的运用)
6366. 在网格图中访问一个格子的最少时间(dijkstra在矩阵上的运用)
|
1月前
|
机器学习/深度学习 算法 测试技术
【单源最短路 图论】882. 细分图中的可到达节点
【单源最短路 图论】882. 细分图中的可到达节点
|
1月前
|
算法 测试技术 C#
【二分图】【二分图最大匹配】LCP 04. 覆盖
【二分图】【二分图最大匹配】LCP 04. 覆盖
|
3月前
|
测试技术
【深度优先搜索】【组合数学】【动态规划】1467.两个盒子中球的颜色数相同的概率
【深度优先搜索】【组合数学】【动态规划】1467.两个盒子中球的颜色数相同的概率
|
9月前
|
算法 C++
探索最小生成树:连通世界的最短纽带
生活中,我们常常需要在一组地点之间建立联系,这些联系可能是道路、管道、电缆等。然而,资源有限,成本宝贵。在这种情况下,如何以最小的代价将这些地点连接起来,成为了一个关键问题。这就引出了图论中的一个重要概念:最小生成树(Minimum Spanning Tree,MST)。本文将通过一个日常生活的案例,详细探讨最小生成树的概念、应用。
52 0