POJ2942 Knights of the Round Table【Tarjan点双联通分量】【二分图染色】【补图】

LINK


题目大意

有一群人,其中有一些人之间有矛盾,现在要求选出一些人形成一个环,这个环要满足如下条件:

1.人数大于1

2.总人数是奇数

3.有矛盾的人不能相邻

问有多少人不能和任何人形成任何的环

思路

发现如果在原图上直接判断非常的不方便

考虑在补图上挖掘性质

补图:

补图和原图没有任何一条重边

不图和原图的所有边并集是一个完全图

即删去所有存在的边,把不存在的边加上

发现可以选出来的环在补图上一定是一个奇环

那么就可以考虑怎么找到补图中的所有奇环

  • 性质1:包含一个奇环的点双连通分量中的每一个点一定属于某一个奇环

这个性质还挺神奇的

因为这个点双联通分量中的每两个点之间至少有两条点不相交路径

所以假设一个偶环包含了一个奇环中的一部分\(p_u...p_v\)

因为p是奇环所以\(p_u\)\(p_v\)中一定有一条长度是奇数的路径和一条长度是偶数的路径

所以结论成立咯

所以就可以发现只需要对每个强连通分量判断包不包含奇环就可以了

  • 性质2:包含奇环的充分必要条件是二分图染色冲突

还挺好证明的吧

如果二分图染色不出现冲突,就是个二分图了

二分图中是没有奇环的

所以直接点双联通判一下有没有奇环就可以了


毒瘤poj上有多组数据

注意清零的问题

特别是二分图染色的数组


//Author: dream_maker
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
//----------------------------------------------
//typename
typedef long long ll;
//convenient for
#define fu(a, b, c) for (int a = b; a <= c; ++a)
#define fd(a, b, c) for (int a = b; a >= c; --a)
#define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
//inf of different typename
const int INF_of_int = 1e9;
const ll INF_of_ll = 1e18;
//fast read and write
template <typename T>
void Read(T &x) {
  bool w = 1;x = 0;
  char c = getchar();
  while (!isdigit(c) && c != '-') c = getchar();
  if (c == '-') w = 0, c = getchar();
  while (isdigit(c)) {
    x = (x<<1) + (x<<3) + c -'0';
    c = getchar();
  }
  if (!w) x = -x;
}
template <typename T>
void Write(T x) {
  if (x < 0) {
    putchar('-');
    x = -x; 
  }
  if (x > 9) Write(x / 10);
  putchar(x % 10 + '0');
}
//----------------------------------------------
const int N = 1e3 + 10;
const int M = 1e6 + 10;
struct Edge{
  int u, v, nxt;
} E[M << 1];
int g[N][N], n, m, in[N];
int head[N], tot, vis[N], col[N];
void add(int u, int v) {
  ++tot;
  E[tot].u = u;
  E[tot].v = v;
  E[tot].nxt = head[u];
  head[u] = tot;
}
void clean() {
  memset(head, 0, sizeof(head));
  tot = 0;
}
bool dfs(int u, int now) {
  col[u] = now;
  for (int i = head[u]; i; i = E[i].nxt) {
    int v = E[i].v;
    if (!in[v]) continue;
    if (col[v] && col[v] == col[u]) return 1;
    else if (!col[v] && dfs(v, 3 - now)) return 1; 
  }
  return 0;
}
namespace Tarjan {
int dfn[N], low[N], bel[N];
int ind = 0, cnt_bcc = 0;
stack<Edge> st;
vector<int> bcc[N];
void init() {
  memset(dfn, 0, sizeof(dfn));
  memset(low, 0, sizeof(low));
  memset(bel, 0, sizeof(bel));
  ind = 0;
}
void tarjan(int u, int fa) {
  dfn[u] = low[u] = ++ind;
  for (int i = head[u]; i; i = E[i].nxt) {
    int v = E[i].v;
    if (v == fa) continue;
    if (!dfn[v]) {
      st.push(E[i]);
      tarjan(v, u);
      low[u] = min(low[u], low[v]);
      if (low[v] >= dfn[u]) {
        ++cnt_bcc;
        bcc[cnt_bcc].clear();
        Edge now;
        do {
          now = st.top(); st.pop();
          if (bel[now.u] != cnt_bcc) {
            bel[now.u] = cnt_bcc;
            bcc[cnt_bcc].push_back(now.u);
          } 
          if (bel[now.v] != cnt_bcc) {
            bel[now.v] = cnt_bcc;
            bcc[cnt_bcc].push_back(now.v);
          }
        } while (now.u != u || now.v != v);
        fv(j, bcc[cnt_bcc]) in[bcc[cnt_bcc][j]] = 1;
        if (dfs(bcc[cnt_bcc][0], 1))
          fv(j, bcc[cnt_bcc]) vis[bcc[cnt_bcc][j]] = 1;
        fv(j, bcc[cnt_bcc]) in[bcc[cnt_bcc][j]] = col[bcc[cnt_bcc][j]] = 0;
      }
    } else {
      if (dfn[v] < dfn[u]) {
        st.push(E[i]);
        low[u] = min(low[u], dfn[v]);
      }
    }
  }
}
}
using namespace Tarjan;
int main() {
  freopen("input.txt", "r", stdin);
  while (1) {
    Read(n), Read(m);
    if (!n && !m) return 0;
    tot = 0;
    fu(i, 1, n) head[i] = vis[i] = 0;
    init();
    fu(i, 1, n) 
      fu(j, 1, n)
        g[i][j] = (i == j);
    fu(i, 1, m) {
      int u, v; Read(u), Read(v);
      g[u][v] = g[v][u] = 1;
    }
    fu(i, 1, n)
      fu(j, 1, n)
        if (!g[i][j])
          add(i, j);
    fu(i, 1, n) if (!dfn[i]) tarjan(i, 0);
    int ans = n;
    fu(i, 1, n) if (vis[i]) --ans;
    Write(ans), putchar('\n');
  }
  return 0;
}

转载于:https://www.cnblogs.com/dream-maker-yk/p/9858203.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园的建设目标是通过数据整合、全面共享,实现校园内教学、科研、管理、服务流程的数字化、信息化、智能化和多媒体化,以提高资源利用率和管理效率,确保校园安全。 智慧校园的建设思路包括构建统一支撑平台、建立完善管理体系、大数据辅助决策和建设校园智慧环境。通过云架构的数据中心与智慧的学习、办公环境,实现日常教学活动、资源建设情况、学业水平情况的全面统计和分析,为决策提供辅助。此外,智慧校园还涵盖了多媒体教学、智慧录播、电子图书馆、VR教室等多种教学模式,以及校园网络、智慧班牌、校园广播等教务管理功能,旨在提升教学品质和管理水平。 智慧校园的详细方案设计进一步细化了教学、教务、安防和运维等多个方面的应用。例如,在智慧教学领域,通过多媒体教学、智慧录播、电子图书馆等技术,实现教学资源的共享和教学模式的创新。在智慧教务方面,校园网络、考场监控、智慧班牌等系统为校园管理提供了便捷和高效。智慧安防系统包括视频监控、一键报警、阳光厨房等,确保校园安全。智慧运维则通过综合管理平台、设备管理、能效管理和资产管理,实现校园设施的智能化管理。 智慧校园的优势和价值体现在个性化互动的智慧教学、协同高效的校园管理、无处不在的校园学习、全面感知的校园环境和轻松便捷的校园生活等方面。通过智慧校园的建设,可以促进教育资源的均衡化,提高教育质量和管理效率,同时保障校园安全和提升师生的学习体验。 总之,智慧校园解决方案通过整合现代信息技术,如云计算、大数据、物联网和人工智能,为教育行业带来了革命性的变革。它不仅提高了教育的质量和效率,还为师生创造了一个更加安全、便捷和富有智慧的学习与生活环境。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值