【做题笔记】网络流24题

Part1.飞行员配对方案问题#

Problem#

有两个集合 AB。给定正整数 nmA={x|1xm}B={y|m+1yn}

现在要将 AB 集合的元素一一配对,有若干个配对关系,形如“u, v 可凑一对”。

求有多少个元素能配成一对,并求出方案。

Solve#

裸的二分图,但是网络流来写。明明匈牙利可以过,但这是网络流的题,所以用网络流做

配对关系可以转换成连边关系,如果 uv 可以配对,就将 uv,容量为 1

创建两个点,源点 s,汇点 t。然后将 s 连向集合 A 的所有点,集合 B 的所有点连向 t,容量为 1。在用此图跑最大流即可。汇点的最大流即为配对的个数。

由于要求方案,要在 EK 增广的时候记录所配对的点。因为一个增广路上的除去源点和汇点所有点,都会配对。

记得建反边!!

Code#

#include <bits/stdc++.h>
#define int long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
#define inf LLONG_MAX

using namespace std;

inline int read() {
  rint x=0,f=1;char ch=getchar();
  while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
  while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
  return x*f;
}

void print(int x){
  if(x<0){putchar('-');x=-x;}
  if(x>9){print(x/10);putchar(x%10+'0');}
  else putchar(x+'0');
  return;
}

const int N = 1e5 + 10;

struct Node {
  int v, w, nx;
} e[N << 1];

int n, m, s = 0, t = 114, tot = 1, h[N], w[N], ansn, last[N], ans[N];

void add(int u, int v, int w) {
  e[++tot].v = v;
  e[tot].w = w;
  e[tot].nx = h[u];
  h[u] = tot;
}

int bfs() {
  memset(last, -1, sizeof last);
  queue<int> q;
  q.push(s);
  w[s] = inf;
  while(!q.empty()) {
    int x = q.front();
    q.pop();
    if(x == t) break;
    for (int i = h[x]; i; i = e[i].nx) {
      int y = e[i].v, w_ = e[i].w;
      if(w_ > 0 && last[y] == -1) {
        w[y] = min(w[x], w_);
        last[y] = i;
        q.push(y);
      }
    }
  } 
  return last[t] != -1;
}

int EK() {
  int res = 0;
  while(bfs()) {
    res += w[t];
    for (int i = t; i != s; i = e[last[i] ^ 1].v) {
      ans[e[last[i] ^ 1].v] = i;
      e[last[i]].w -= w[t];
      e[last[i] ^ 1].w += w[t]; 
    } 
  }
  return res;
}

signed main() {
  m = read(), n = read();
  For(i,1,m) add(s, i, 1), add(i, s, 0);
  For(i,m+1,n) add(i, t, 1), add(t, i, 0);
  while(1) {
    int u = read(), v = read();
    if(u == -1 && v == -1) break;
    add(u, v, 1);
    add(v, u, 0);
  }
  ansn = EK();
  cout << ansn << '\n';
  For(i,1,m) {
    if(!ans[i] || ans[i] == 114) continue;
    cout << ans[i] << ' ' << i << '\n';
  }
  return 0;
}

作者:Daniel-yao

出处:https://www.cnblogs.com/Daniel-yao/p/17624964.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Daniel_yzy  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示