zoukankan      html  css  js  c++  java
  • P2071 座位安排——二分图最大匹配

    P2071 座位安排

    题目背景

    公元二零一四年四月十七日,小明参加了省赛,在一路上,他遇到了许多问题,请你帮他解决。

    题目描述

    已知车上有(N)排座位,有(N*2)个人参加省赛,每排座位只能坐两人,且每个人都有自己想坐的排数,问最多使多少人坐到自己想坐的位置。

    输入格式

    第一行,一个正整数(N)

    第二行至第(N*2+1)行,每行两个正整数(Si_1)(Si_2),为每个人想坐的排数。

    输出格式

    一个非负整数,为最多使得多少人满意。

    输入输出样例

    输入 #1复制

    4
    1 2
    1 3
    1 2
    1 3
    1 3
    2 4
    1 3
    2 3
    

    输出 #1复制

    7
    

    说明/提示

    对于10%的数据 N≤10

    对于30%的数据 N≤50

    对于60%的数据 N≤200

    对于100%的数据 N≤2000

    算法提示:二分图的最大匹配

    思路

    二分图的最大匹配

    把人看成是男生,座椅看成是(2*n)个女生

    但是这道题一排有两个点,怎么办

    我们可以自然地想到,并查集的扩展域

    相同的,我们迁移到这道题,一排不是有两个座位吗,我们不是不知道那个连那个吗,直接加个(n)把他们分开不就好了

    add(i,x);
    add(i,s);
    add(i,x+n);
    add(i,s+n);
    

    这样我们就可以把男生看成左部点,女生看成右部点,分成完全独立的两部分了

    小优化,从minxu那里学到的,可以不用每次都memset的方法,就是你记一个时间戳

    每次小于时间的才更新的,和memset0一个效果,具体为什么的见我的这一篇博客

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 200000;
    int ne[N], head[N], ver[N], idx;
    int match[N], st[N];
    int tim;
    int n, m;
    int res;
    void add(int u, int v) {
      ne[idx] = head[u];
      ver[idx] = v;
      head[u] = idx;
      idx++;
    }
    
    int find(int x) {
      for (int i = head[x]; i != -1; i = ne[i]) {
        int j = ver[i];
        if (st[j] < tim) {
          st[j] = tim;
          if (match[j] == 0 || find(match[j]) == 1) {
            match[j] = x;
            return 1;
          }
        }
      }
      return 0;
    }
    
    int main() {
      memset(head, -1, sizeof(head));
      scanf("%d", &n);
      for (register int i = 1; i <= n * 2; i++) {
        int s, x;
        scanf("%d%d", &s, &x);
        add(i, s);
        add(i, x);
        add(i, s + n);
        add(i, x + n);
      }
      for (register int i = 1; i <= n * 2; i++) {
        ++tim;
        if (find(i)) res++;
      }
      cout << res << endl;
      return 0;
    }
    
  • 相关阅读:
    关于标准库中的ptr_fun/binary_function/bind1st/bind2nd
    ptr_fun学习笔记
    stream_iterator、ostream_iterator 使用初探
    C++异常处理
    ext2文件系统
    C语言动态内存管理
    C++中为什么要用虚函数、指针或引用才能实现多态?
    hadoop本地库
    二分图最小点覆盖König定理的简单证明 (加入自己理解)
    Fence Repair POJ
  • 原文地址:https://www.cnblogs.com/bangdexuanyuan/p/14075168.html
Copyright © 2011-2022 走看看