Acwing 376.机器任务 (最小点覆盖)

简介: 笔记

Acwing 376.机器任务


题意

有两台机器 A,B以及 K 个任务。


机器 A 有 N种不同的模式(模式0 ∼ N − 1 ),机器 B 有 M 种不同的模式(模式 0 ∼ M − 1)。


两台机器最开始都处于模式 0。


每个任务既可以在 A上执行,也可以在 B 上执行。


对于每个任务 i,给定两个整数a[i] 和b[i],表示如果该任务在A 上执行,需要设置模式为 a[i],如果在B 上执行,需要模式为b[i]。


任务可以以任意顺序被执行,但每台机器转换一次模式就要重启一次。


求怎样分配任务并合理安排顺序,能使机器重启次数最少。


思路

将机器A的所有模式看作左边的集合,机器B 的所有模式看作右边的集合,模式看作顶点,任务看作连接机器 A 和机器 B 的一条边,原题可以抽象成一个二分图。那么题目要求的就是,在这张二分图中最少选多少个顶点(模式),可以覆盖所有的边(任务),即最小点覆盖问题。 而我们又知道在二分图中 最小点覆盖 == 最大匹配数,所以直接用匈牙利算法求二分图的最大匹配即可。


需要注意的是,两台机器最初都处于模式0,所以不用转换模式即可将a[i] 或b[i] 为0的任务完成,所以建图时将这种情况忽略即可。


代码

// Author:zzqwtcc
// Problem: 机器任务
// Contest: AcWing
// Time:2021-10-07 14:17:44
// URL: https://www.acwing.com/problem/content/378/
// Memory Limit: 10 MB
// Time Limit: 1000 ms
#include<bits/stdc++.h>
#include<unordered_map>
// #define int long long
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3f
#define mod 1000000007
#define MOD 998244353
#define rep(i, st, ed) for (int (i) = (st); (i) <= (ed);++(i))
#define pre(i, ed, st) for (int (i) = (ed); (i) >= (st);--(i))
#define debug(x,y) cerr << (x) << " == " << (y) << endl;
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
template<typename T> inline T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<typename T> inline T lowbit(T x) { return x & -x; }
// template<typename T> T qmi(T a, T b = mod - 2, T p = mod) { T res = 1; b %= (p - 1 == 0 ? p : p - 1); while (b) { if (b & 1) { res = (LL)res * a % p; }b >>= 1; a = (LL)a * a % p; }return res % mod; }
const int N = 110;
int n,m,k;
vector<int>vec[N];
bool st[N];
int match[N];
bool find(int u){
  for(int i =0 ; i < vec[u].size();++i){
    int j =vec[u][i];
    if(st[j])continue;
    st[j] = true;
    if(match[j] == -1 || find(match[j])){
      match[j] = u;
      return true;
    }
  }
  return false;
}
void solve() {
    while(cin >> n, n){
      for(int i = 0 ;i <= 100;++i)vec[i].clear();
      memset(match,-1,sizeof match);
      cin >> m >> k;
      while(k--){
        int id,u,v;cin >> id >> u >> v;
        if(u && v)
          vec[u].push_back(v);
      }
      int res = 0;
      for(int i = 0; i <= n;++i){
        memset(st,0,sizeof st);
        if(find(i))
          res++;
      }
      for(int i = 0; i <= m;++i){
          if(match[i] == 0){
              res--;
              break;
          }
      }
      cout << res << endl;
    }
}
signed main() {
    // int _; cin >> _;
    // while (_--)
        solve();
    return 0;
}


目录
相关文章
|
Linux 数据安全/隐私保护 iOS开发
Linux下SVN 命令每次都要输入密码
Linux下SVN 命令每次都要输入密码
|
机器学习/深度学习
|
机器学习/深度学习
移动字母(蓝桥杯—12年困难题)
移动字母(蓝桥杯—12年困难题)
239 0
|
4天前
|
云安全 人工智能 安全
AI被攻击怎么办?
阿里云提供 AI 全栈安全能力,其中对网络攻击的主动识别、智能阻断与快速响应构成其核心防线,依托原生安全防护为客户筑牢免疫屏障。
|
14天前
|
域名解析 人工智能
【实操攻略】手把手教学,免费领取.CN域名
即日起至2025年12月31日,购买万小智AI建站或云·企业官网,每单可免费领1个.CN域名首年!跟我了解领取攻略吧~
|
8天前
|
安全 Java Android开发
深度解析 Android 崩溃捕获原理及从崩溃到归因的闭环实践
崩溃堆栈全是 a.b.c?Native 错误查不到行号?本文详解 Android 崩溃采集全链路原理,教你如何把“天书”变“说明书”。RUM SDK 已支持一键接入。
567 211
|
4天前
|
编解码 Linux 数据安全/隐私保护
教程分享免费视频压缩软件,免费视频压缩,视频压缩免费,附压缩方法及学习教程
教程分享免费视频压缩软件,免费视频压缩,视频压缩免费,附压缩方法及学习教程
228 138