首页 > 其他分享 >CF1835F Good Graph

CF1835F Good Graph

时间:2024-11-14 15:21:57浏览次数:1  
标签:Good int Graph rep CF1835F vec col match low

小清新图论题。

题目大概说了个关于 hall 定理的东西,不多赘述了。

先处理 NO,这是好处理的,在跑匈牙利的时候如果失配那就把增广到的点集输出即可。

然后处理 YES,注意到两个紧密的集合合并还是紧密的集合。那么我们考虑对每个左部点 \(u\) 找到最小的包含他的紧密的集合 \(S_u\),这个东西怎么求呢?考虑到紧密集合显然是完美匹配的,那么我们直接跑这张图,对于点 \(u\),考虑任意 \(match_v\) 不为 \(u\) 且与 \(u\) 相邻的右部点 \(v\),显然与这些右部点匹配的点都要加入集合,那么我们考虑将 \(u\) 向所有 \(match_v\) 连一条有向边,那么 \(S_u\) 由一张极大闭合子图组成。考虑先跑一遍传递闭包,过程与 floyd 相似,并不是什么高级的东西。然后缩点,然后同一强连通分量中的点是要一一连边的,显然这是最优方案,对于 DAG 上的其它边 \(x\rightarrow y\),考虑是否存在 \(z\) 使得 \(x\rightarrow z\rightarrow y\),若存在则不需要连边,因为这条边是多余的。否则就连。哦对了,一定要把原来匹配好的边加入答案边集。

传递闭包可以用 bitset 实现,所以理论最优复杂度为 \(\mathcal{O}(n^{2.5}+\frac{n^3}{w})\)。但我因为我懒得写 dinic 了,所以写了复杂度更劣的匈牙利,但是可能跑的更快。

代码:

#include <bits/stdc++.h>
#define rep(i, l, r) for (int i (l); i <= (r); ++ i)
#define rrp(i, l, r) for (int i (r); i >= (l); -- i)
#define pii pair <int, int>
#define eb emplace_back
#define ls p << 1
#define rs ls | 1
using namespace std;
constexpr int N = 1e3 + 5;
typedef unsigned long long ull;
typedef long long ll;
inline int rd () {
  int x = 0, f = 1;
  char ch = getchar ();
  while (! isdigit (ch)) {
    if (ch == '-') f = -1;
    ch = getchar ();
  }
  while (isdigit (ch)) {
    x = (x << 1) + (x << 3) + ch - 48;
    ch = getchar ();
  }
  return x * f;
}
vector <int> e[N];
int n, m;
bool vis[N << 1];
int match[N << 1];
bool dfs (int u) {
  for (auto v : e[u]) {
    if (vis[v]) continue; vis[v] = 1;
    if (! match[v] || dfs (match[v])) {
      match[v] = u;
      match[u] = v;
      return 1;
    }
  } return 0;
}
int S[N], tot;
vector <int> G[N], vec[N];
bitset <N> A[N], B[N], E[N], f[N];
int stk[N], top;
int col[N], cnt;
int dfn[N], low[N], tim;
void tarjan (int u) {
  stk[++ top] = u, vis[u] = 1;
  dfn[u] = low[u] = ++ tim;
  for (auto v : G[u]) {
    if (! dfn[v]) {
      tarjan (v);
      low[u] = min (low[u], low[v]);
    } else if (vis[v]) low[u] = min (low[u], dfn[v]);
  }
  if (low[u] == dfn[u]) {
    int k = 0; ++ cnt;
    while (k ^ u) {
      k = stk[top --]; vis[k] = 0;
      col[k] = cnt;
    }
  }
}
vector <pii> ans;
int main () {
  // freopen ("1.in", "r", stdin);
  // freopen ("1.out", "w", stdout);
  n = rd (), m = rd ();
  rep (i, 1, m) {
    int u = rd (), v = rd ();
    e[u].eb (v);
  }
  rep (i, 1, n) {
    if (! dfs (i)) {
      rep (j, n + 1, n * 2) if (vis[j]) {
        S[++ tot] = match[j];
      }
      S[++ tot] = i;
      puts ("NO");
      printf ("%d\n", tot);
      rep (i, 1, tot) printf ("%d ", S[i]);
      return 0;
    }
    memset (vis, 0, sizeof vis);
  }
  puts ("YES");
  rep (u, 1, n) {
    f[u][u] = 1;
    for (auto v : e[u]) {
      if (match[v] && match[v] != u) {
        G[u].eb (match[v]); f[u][match[v]] = 1;
      }
    }
    ans.eb (pii (u, match[u]));
  }
  rep (j, 1, n) {
    rep (i, 1, n) {
      if (f[i][j]) f[i] |= f[j];
    }
  }
  rep (i, 1, n) if (! dfn[i]) tarjan (i);
  rep (i, 1, n) vec[col[i]].eb (i);
  rep (i, 1, cnt) {
    if (vec[i].size () == 1) continue;
    for (int j = 0; j < vec[i].size (); ++ j) {
      ans.eb (pii (vec[i][j], match[vec[i][(j + 1) % vec[i].size ()]]));
    }
  }
  rep (u, 1, n) for (auto v : G[u]) if (col[u] ^ col[v]) E[col[u]][col[v]] = 1;
  rep (i, 1, cnt) A[i][i] = B[i][i] = 1;
  rep (i, 1, n) {
    rep (j, 1, n) {
      if (f[i][j]) {
        A[col[i]][col[j]] = B[col[j]][col[i]] = 1;
      }
    }
  }
  rep (i, 1, cnt) {
    rep (j, 1, cnt) {
      if (! E[i][j]) continue;
      if ((A[i] & B[j]).count () == 2) {
        ans.eb (pii (vec[i][0], match[vec[j][0]]));
      }
    }
  }
  printf ("%ld\n", ans.size ());
  for (auto p : ans) printf ("%d %d\n", p.first, p.second);
}

标签:Good,int,Graph,rep,CF1835F,vec,col,match,low
From: https://www.cnblogs.com/lalaouyehome/p/18546049

相关文章

  • 基于华为云FunctionGraph和ModelArts的智能动漫头像生成:从自拍到AI风格化的编程
    文章目录1引言2背景介绍2.1华为云FunctionGraph与ModelArts简介3项目准备3.1注册与登录华为云账号4实验步骤4.1首先我们配置云主机4.2安装FunctionGraph插件4.3创建函数4.4部署函数4.5函数配置委托4.6函数配置触发器4.7函数添加依赖包4.8订阅模型并部署A......
  • 【菜笔cf刷题日常-1600】C. Good Subarrays(思维,前缀和)
    链接:Problem-1398C-Codeforces思路:考虑每一个新加入的数对于原有序列(长度、数的总和)需求的变化:如1的加入对于原有序列需求无变化;2 的加入需要原有序列长度增加1;0 的加入需要原有序列数的总和增加1;……因此,将每个数减1(如1变为0,0变为 -1)来代表这个数的......
  • Solution - Codeforces 1394B Boboniu Walks on Graph
    考虑先分析最后的图会长成什么样。因为每个点都只会连出一条有向边,且最后还能走回自己。所以可以知道的是图会有许多个环来组成,且每个环都无交。但是这个判定条件明显不是很优秀,考虑继续转化。考虑到对于一个有向环,每个点的出度和入度都需要为\(1\)。那么出度为\(1\)题目......
  • LangGraph高级特性:总结与注意事项
    LangGraph作为一个强大的图结构程序设计工具,提供了许多高级特性来支持复杂的AI应用开发。本文将深入探讨LangGraph的一些关键概念和注意事项,帮助开发者更好地利用这个工具。1.数据状态与归纳函数在LangGraph中,理解数据状态的处理方式至关重要。默认情况下,节点返回的字典数据会......
  • LangGraph的两种基础流式响应技巧
    在构建复杂的AI应用时,LangGraph作为一个强大的工具,为我们提供了灵活的图结构程序设计能力。今天,我们将深入探讨LangGraph中的一个关键特性:流式响应模式。这个特性不仅能提高应用的响应速度,还能为用户提供更加流畅的交互体验。LangGraph中的流式响应:与传统LLM有何不同?在LangGraph......
  • 大数据Flink - StreamGraph
    ⭐简单说两句⭐✨正在努力的小新~......
  • 密码学之MD5(Cryptography MD5)
      ......
  • LangGraph中的检查点与人机交互
    一、LangGraph的检查点机制检查点机制是LangGraph中一个强大的功能,它允许我们在图执行的特定点暂停处理,保存状态,并在需要时恢复。1.1检查点的基本概念检查点本质上是图执行过程中的一个快照,包含了当前的状态信息。这对于长时间运行的任务、需要人工干预的流程,或者需要断点续传......
  • 使用LangGraph构建复杂AI工作流:子图架构详解
    一、子图架构概述子图(Subgraph)是LangGraph中一个强大的特性,它允许我们将复杂的工作流程分解成更小、更易管理的组件。通过子图,我们可以实现模块化设计,提高代码的可重用性和可维护性。1.1子图的基本概念子图本质上是一个完整的图结构,可以作为更大图结构中的一个节点使用。它具......
  • LangGraph入门:构建ReACT架构的智能Agent
    引言在人工智能和大语言模型(LLM)快速发展的今天,如何构建高效、灵活的智能Agent成为了一个热门话题。LangGraph作为一个强大的工具,为我们提供了一种新的方式来实现复杂的AI工作流,特别是在构建ReACT(ReasoningandActing)架构的智能Agent方面表现出色。本文将深入探讨如何使用LangGra......