la3523 白书例题 圆桌骑士 双联通分量+二分图

具体题解看大白书P316

#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>
#include <stack>
#include <cstdio>
using namespace std;
struct Edge{int u,v;};
const int maxn = 1000+10;
int pre[maxn],iscut[maxn],bccno[maxn],dfs_clock,bcc_cnt;
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++; bcc[bcc_cnt].clear();
                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;
    return lowu;
}
void find_bcc(int n){
    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[u] == color[v]) 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;
             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;
}

时间: 2024-10-08 10:03:53

la3523 白书例题 圆桌骑士 双联通分量+二分图的相关文章

UvaLive3523 Knights of the Round Table(点双联通分量+二分图染色)

UvaLive3523 Knights of the Round Table 参考了Kuangbin巨的题解. /* POJ 2942 Knights of the Round Table 亚瑟王要在圆桌上召开骑士会议,为了不引发骑士之间的冲突, 并且能够让会议的议题有令人满意的结果,每次开会前都必须对出席会议的骑士有如下要求: 1. 相互憎恨的两个骑士不能坐在直接相邻的2个位置: 2. 出席会议的骑士数必须是奇数,这是为了让投票表决议题时都能有结果. 注意:1.所给出的憎恨关系一定是双向的,不

【POJ 2942】Knights of the Round Table(双联通分量+染色判奇环)

[POJ 2942]Knights of the Round Table(双联通分量+染色判奇环) Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 11661   Accepted: 3824 Description Being a knight is a very attractive career: searching for the Holy Grail, saving damsels in distress, an

双联通分量与二分图

我这是耽搁了多长时间才把它整完哈哈哈哈哈: 双联通分量 在无向图中,如果无论删去哪条边都不能使得 u 和 v 不联通,则称 u 和 v 边双连通: 在无向图中,如果无论删去哪个点(非 u 和 v)都不能使得 u 和v 不联通,则称 u 和 v 点双连通. 割点:删去该点,图分裂为多个连通块. 割边:也叫"桥",删去该边,图分裂为多个连通块. 点双连通分量 类似地,定义$ d f n_u 和 low_u$. 如果 v 是 u 的子结点,并且 $low_v ≥ d f n_u $则点 u

hihocoder #1190 : 连通性&#183;四 点双联通分量

http://hihocoder.com/problemset/problem/1190?sid=1051696 先抄袭一下 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho从约翰家回到学校时,网络所的老师又找到了小Hi和小Ho. 老师告诉小Hi和小Ho:之前的分组出了点问题,当服务器(上次是连接)发生宕机的时候,在同一组的服务器有可能连接不上,所以他们希望重新进行一次分组.这一次老师希望对连接进行分组,并把一个组内的所有连接关联的服务器也视为这个组内

[HDOJ4738]Caocao&#39;s Bridges(双联通分量,割边,tarjan)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4738 给一张无向图,每一条边都有权值.找一条割边,使得删掉这条边双连通分量数量增加,求权值最小那条. 注意有重边,ACEveryDay里群巨给的意见是tarjan的时候记录当前点是从哪条边来的. 注意假如桥的权值是0的时候也得有一个人去炸…… 1 /* 2 ━━━━━┒ギリギリ♂ eye! 3 ┓┏┓┏┓┃キリキリ♂ mind! 4 ┛┗┛┗┛┃\○/ 5 ┓┏┓┏┓┃ / 6 ┛┗┛┗┛┃ノ) 7

UVA - 10765 Doves and bombs (双联通分量)

链接 :  http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34798 给N个点的无向图并且联通,问删除每次一个点之后还剩多少联通分量. 找割顶 如果删除的是割顶 联通分量就会增加,否则还是1(因为原图是联通图),删除割顶之后 联通块的数目 就要看该割顶在几个双联通分量里出现过. #pragma comment(linker, "/STACK:10240000,10240000") #include <a

HDU5409---CRB and Graph 2015多校 双联通分量缩点

题意:一个联通的无向图, 对于每一条边, 若删除该边后存在两点不可达,则输出这两个点, 如果存在多个则输出第一个点尽可能大,第二个点尽可能小的. 不存在输出0 0 首先 若删除某一条边后存在多个联通分量则该边一定是桥, 那么我们可以先处理出所有的桥,然后把所有双联通分量缩点,缩点之后就变成了一棵树. 而树上的每一条边都是一个桥, 考虑每条边的输出,删除某一边后肯定会出现两个联通分量, 需要记录两个联通分量中最大的点max1 max2, 如果max1!=n 则答案就是max1 max1+1否则ma

poj2942 Knights of the Round Table,无向图点双联通,二分图判定

点击打开链接 无向图点双联通,二分图判定 <span style="font-size:18px;">#include <cstdio> #include <stack> #include <vector> #include <algorithm> #include <cstring> using namespace std; struct Edge{ int u, v; }; const int maxn = 1

BZOJ2730 矿场搭建 解题报告 点双联通分量

题意概述: 一张有向图,在其中设置一些关键点(即题目中的逃生出口),使得删除任意一个点之后其余点都可以到达至少一个关键点. 问至少需要设置多少中关键点,有多少种设置方法. 解析: 首先,这道题要求删掉一个点,不难想到这道题与割点有关.其次,删掉一个点其他点仍然可以到达关键点就可以想到是点双联通分量. 但是,问题关键是,真的需要在每一个点双联通分量中都设置一个关键点吗? 答案是否定的,因为如果一个双联通分量连接了两个或两个以上的割点,一个割点被删掉那么还可以通过另外的割点到达某个关键点,如上图,红