圆桌骑士,蓝书P316LA3523(tarjan求双连通分量算法,二分图判断,奇圈)

原创 2017年11月14日 20:01:55

重点重点重点,每一个不在环内的边本身也是单独的一个双连通分量。双连通分量定义:若一个无向图中的去掉任意一个节点(一条边)都不会改变此图的连通性,即不存在割点(桥),则称作点(边)双连通图。刘汝佳白书P314也给出了这个等价定义,但是“任意两点之间至少存在两条点不重复的路径”这个定义明显不包含单独边这种情况。tarjan算法都是基于标准定义的。

本题目的经典程度不用多赘述。直接总结:
1.Edge e = (Edge){u, v};//此处语法细节需要学习 结构体 的初始化方式。
2.if(fa < 0 && child == 1) iscut[u] = 0;//当fa<0且child == 1的时候,就是一条边,对于一条边无割顶
3.bccno数组标记当前访问的连通分量的点。
4.用color数组来判断是否为二分图。

// LA3523 Knights of the Round Table
// Rujia Liu
#include<cstdio>
#include<stack>
#include<vector>
#include<algorithm>
#include<cstring>

using namespace std;

struct Edge { int u, v; };

const int maxn = 1000 + 10;
int pre[maxn], iscut[maxn], bccno[maxn], dfs_clock, bcc_cnt; // 割顶的bccno无意义
vector<int> G[maxn], bcc[maxn];

stack<Edge> S;

int dfs(int u, int fa) {
  int lowu = pre[u] = ++dfs_clock;
  int child = 0;
  for(int i = 0; i < G[u].size(); i++) {
    int v = G[u][i];
    Edge e = (Edge){u, v};//此处语法细节需要学习 
    if(!pre[v]) { // 没有访问过v
      S.push(e);
      child++;
      int lowv = dfs(v, u);
      lowu = min(lowu, lowv); // 用后代的low函数更新自己
      if(lowv >= pre[u]) {
        iscut[u] = true;
        bcc_cnt++; 
        for(;;) {
          Edge x = S.top(); S.pop();
          if(bccno[x.u] != bcc_cnt) { bcc[bcc_cnt].push_back(x.u); bccno[x.u] = bcc_cnt; }
          if(bccno[x.v] != bcc_cnt) { bcc[bcc_cnt].push_back(x.v); bccno[x.v] = bcc_cnt; }
          if(x.u == u && x.v == v) break;
        }
      }
    }
    else if(pre[v] < pre[u] && v != fa) {
      S.push(e);
      lowu = min(lowu, pre[v]); // 用反向边更新自己
    }
  }
  if(fa < 0 && child == 1) iscut[u] = 0;//当fa<0且child == 1的时候,就是一条边,对于一条边无割顶 
  return lowu;
}

void find_bcc(int n) {
  // 调用结束后S保证为空,所以不用清空
  memset(pre, 0, sizeof(pre));
  memset(iscut, 0, sizeof(iscut));
  memset(bccno, 0, sizeof(bccno));
  dfs_clock = bcc_cnt = 0;
  for(int i = 0; i < n; i++)
    if(!pre[i]) dfs(i, -1); 
}

int odd[maxn], color[maxn];
bool bipartite(int u, int b) {
  for(int i = 0; i < G[u].size(); i++) {
    int v = G[u][i]; if(bccno[v] != b) continue;
    if(color[v] == color[u]) return false;
    if(!color[v]) {
      color[v] = 3 - color[u];
      if(!bipartite(v, b)) return false;
    }
  }
  return true;
}

int A[maxn][maxn];

int main() {
  int kase = 0, n, m;
  while(scanf("%d%d", &n, &m) == 2 && n) {
    for(int i = 0; i < n; i++) G[i].clear();

    memset(A, 0, sizeof(A));
    for(int i = 0; i < m; i++) {
      int u, v;
      scanf("%d%d", &u, &v); u--; v--; A[u][v] = A[v][u] = 1;
    }
    for(int u = 0; u < n; u++)
      for(int v = u+1; v < n; v++)
        if(!A[u][v]) { G[u].push_back(v); G[v].push_back(u); }//!!!图的邻接存储!!! 

    find_bcc(n);

    memset(odd, 0, sizeof(odd));
    for(int i = 1; i <= bcc_cnt; i++) {
      memset(color, 0, sizeof(color));
      for(int j = 0; j < bcc[i].size(); j++) bccno[bcc[i][j]] = i; // 将所有节点暂时标记为当前要访问的双连通分量,主要是处理割顶
      int u = bcc[i][0];
      color[u] = 1;//二分图一定不是简单奇圈,简单奇圈一定不是二分图 ,刘巧妙用color变量来判断是否为二分图 
      if(!bipartite(u, i))
        for(int j = 0; j < bcc[i].size(); j++) odd[bcc[i][j]] = 1;
    }
    int ans = n;
    for(int i = 0; i < n; i++) if(odd[i]) ans--;
    printf("%d\n", ans);
  }
  return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

【poj2942】圆桌骑士Knights of the Round Table【双连通分量】【二分图】【奇圈】

传送门:http://poj.org/problem?id=2942 尽管我承认这题我几乎是对着书抄的代码(因为我还不熟- -),但是我还是WA了三次- -数组又没清零。 基本思想就是: 首先把...

LA 3523(双连通分量,判断二分图)

以后这个代码用来当模板 #include #include #include #include #include using namespace std; const int maxn=...
  • mtxxxx
  • mtxxxx
  • 2016年11月21日 23:12
  • 88

LA 3523 Knights of the Round Table(点双连通分量+二分图判断)

题意:有n个骑士经常举行圆桌会议,商讨大事,每次圆桌会议至少应有3个骑士参加,且互相憎恨的骑士不能坐在圆桌旁的相邻位置,如果发生意见分歧,则需要举手表决,因此参加会议的骑士数目必须是奇数,以防赞同和反...

poj2942圆桌骑士【点双连通分量+二分图判断】

/*********** poj2942 2015.11.11-2015.11.13 不懂 暂时放下了 2015.11.18 4792K 1172MS G++ ***********/ #includ...

LA 3523 Knights of the Round Table 边双连通分量+二分图判定

收获: 1、面对在图中分离出一个圈的问题时,要想到用无向图的边双连通分量 2、当强调这个圈满足边数的奇偶条件时,要想到和二分图有关 #pragma warning(disable:4786) #...
  • jijijix
  • jijijix
  • 2017年03月14日 17:10
  • 109

poj2942[补图+点双连通分量+交叉染色法判定二分图(奇圈判定)]

Knights of the Round Table Time Limit: 7000MS   Memory Limit: 65536K Total Submissio...

【tarjan求双连通分量+染色判二分图】POJ 2942

这题debug的好郁闷啊!!!先是染色有问题,然后就是各种小错误.... 判奇圈可以用二分图标准,因为奇圈肯定不是二分图,之前还要分离各双连通分量.......染色法判二分图一定要先对分量里每一个点...
  • leolin_
  • leolin_
  • 2012年03月15日 02:08
  • 512

poj 2942 Knights of the Round Table(双连通分量+tarjan+二分图判定)

http://poj.org/problem?id=2942 题意: 有N个骑士,给出某些骑士之间的仇恨关系,骑士们开会时会围坐在一个圆桌旁。一次会议能够顺利举行,要满足两个条件:1:任意相互憎恨的两...

UVAlive 3523 Knights of the Round Table [点双连通分量] [Tarjan]

Knights of the Round Table Time Limit: 4500MS 64bit IO Format: %lld & %lluDescription Bei...

poj 2942 Knights of the Round Table 圆桌骑士(双连通分量模板题)

Knights of the Round Table Time Limit: 7000MS   Memory Limit: 65536K Total Submissio...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:圆桌骑士,蓝书P316LA3523(tarjan求双连通分量算法,二分图判断,奇圈)
举报原因:
原因补充:

(最多只允许输入30个字)