首页 > 其他分享 >[网络流 24 题] 飞行员配对方案问题

[网络流 24 题] 飞行员配对方案问题

时间:2022-11-25 22:11:45浏览次数:67  
标签:24 idx int 建图 集合 飞行员 配对

飞行员配对方案问题

传送门

题目大意

有一群开飞机的,他们分为英国人和非英国人。对于飞行员的进行搭配,设计一个找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。

题目分析

这个题其实是可以用匈牙利算法实现的,时空复杂度\(O(nm)\),观察数据范围,其实是不会超时的。但是使用dinic则可以在\(O(m √n)\)计算完成。

所以本题采用dinic算法。

首先,第一个问题是如何将其转化为最大流问题。转换成最大流问题,首先要满足两个条件

  1. 容量限制

  2. 流量守恒

而转化问题的思想,我们可以参考闫氏dp分析法。在一个解决方案集合内找到最优解,然后对应找到可行流。所以当前问题为如何建图。

我们想把整个题按照二分图的想法,分成两个集合,英国人和外籍,之后进行匹配。匹配的时候打上流量和容量。之后在转化为最大可行流问题,在两个集合的左和右两方(一共两方,比如集合一左方和集合二右方)分别建上源点汇点,之后建图的时候边权设置成1就行了。

建完图之后剩下的就和dinic算法差不多了,但这个题还要输出一个方案,这个时候我们只需要对i=0idx进行遍历输出,但注意,输出的时候由于我们idx在每次建边时跑了两遍,所以i+=2就处理完啦!

代码实现

#include <bits/stdc++.h>
#define rint register int

using namespace std;

const int N = 1e2 + 5;
const int M = 6e3 + 5;
const int INF = 1e8;

int m, n, S, T;
int h[N], e[M], f[M], ne[M], idx;
int q[N], d[N], cur[N];
void add(int a, int b, int c)
{
    e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx++;
    e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx++;
}
bool bfs()
{
    int hh = 0, tt = 0;
    memset(d, -1, sizeof d);
    q[0] = S;
    d[S] = 0;
    cur[S] = h[S];
    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])
            {
                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)
{
    if (u == T)
        return limit;
    int flow = 0;
    for (int i = cur[u]; ~i && flow < limit; i = ne[i])
    {
        cur[u] = 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()
{
    cin >> m >> n;
    S = 0;
    T = n + 1;
    memset(h, -1, sizeof h);
    for (int i = 1; i <= m; i++)
        add(S, i, 1);
    for (int i = m + 1; i <= n; i++)
        add(i, T, 1);
    int a, b;
    while (cin >> a >> b, a != -1)
        add(a, b, 1);

    cout << dinic() << endl;

    for (int i = 0; i < idx; i += 2)
        if (e[i] > m && e[i] <= n && !f[i])
            cout << e[i ^ 1] << " " << e[i] << endl;

    return 0;
}

总结

在网络流的实际应用中,更看重的是建图的能力,而建图能力是要不断做题磨出来的,之后要熟悉算法实现原理,才能保证题目修改输出条件等情况也可以随心应手的解决。

标签:24,idx,int,建图,集合,飞行员,配对
From: https://www.cnblogs.com/spaceswalker-garden/p/16926538.html

相关文章

  • 24.1 SetUnhandledExceptionFilter未处理异常--《Windows核心编程》
    对于未处理异常,例如异常过滤返回EXCEPTION_CONTINUE_SEARCH,向上搜索,但无法搜索到处理部分,产生未处理异常。Windows提供了SetUnhandledExceptionFilter函数,给我们处理异常......
  • 24.3 向量化异常VEH--《Windows核心编程》
    Windows提供了向量化异常处理(vectoredexcepationhanding,VEH)机制。程序可以注册一个函数,每当异常发送或者一个未处理异常脱离标准SEH的控制时,这个函数就会被调用。PVO......
  • pod启动时报错:failed to set bridge addr: "cni0" already has an IP address differe
    今天创建pod的时候,一直不running,describepod后看到报错:Failedcreatepodsandbox:rpcerror:code=Unknowndesc=failedtosetupsandboxcontainer"bb8a1493......
  • Go 语言系列24:go 协程
    Go协程是与其他函数或方法一起并发运行的函数或方法。Go协程可以看作是轻量级线程。与线程相比,创建一个Go协程的成本很小。因此在Go应用中,常常会看到有数以千计的Go......
  • LeetCode 240.搜索二维矩阵II(中等)
    题目描述:编写一个高效的算法来搜索 ​​m x n​​​ 矩阵​​matrix​​​中的一个目标值​​target​​。该矩阵具有以下特性:每行的元素从左到右升序排列。每列的......
  • 2022.11.24
    来了收拾了一阵QQ。鬼知道为什么收拾它。$$感觉今天出题出的很不地道,给我一种我能做出来的错觉,但是浪费了我的感情和时间。粘都懒得粘。$$我留下的奶茶大杯子被打......
  • 20221124
    为什么越来越有种感觉,最终肯定会分开.如果知道结局,还有必要继续下去吗?两个人都没问题。那问题出在哪呢?我太喜欢吃醋了,又是对谁都很活泼开朗的,如果一开始就不认识还好,......
  • LeetCode刷题记录.Day24
    有效的括号20.有效的括号-力扣(LeetCode)classSolution{public:boolisValid(strings){if(s.size()%2!=0)returnfalse;//奇数必不符合......
  • 11.24.7
    #include<stdio.h>intmain(){ intn; scanf("%d",&n); switch(n/10) {case10:case9:printf("A");break; case8:printf("B");break; case7:printf("C");break......
  • 11.24.8
    #include<stdio.h>intmain(){ intn,i,j,a[10]; scanf("%d",&n); for(i=0;;i++) {if(n==0)break; a[i]=n%10; n=n/10; } printf("%d\n",i); for(j=i-1;j>=0;j--......