zoukankan      html  css  js  c++  java
  • uvalive 3523 Knights of the Round Table 圆桌骑士(强连通+二分图)

    题目真心分析不出来。看了白书才明白,不过有点绕脑。

    容易想到,把题目给的不相邻的关系,利用矩阵,反过来建图。既然是全部可行的关系,那么就应该能画出含奇数个点的环。求环即是求双连通分量:找出所有的双连通分量,只要分量中的点数是奇数,则排除“must be expelled”的可能性。

    判环上的点数用二分图,这个我都想了半天= =,如果是奇数个点,明摆着多出来的一个点放到哪个集合都会与集合内的点连边(这个找三个点自己画画试试就明白了)。0、1染色,本人喜欢用bfs,递归什么的其实都可以。

    我自己用缩点做的,果断wa到吐。举个例子:五个点,{1,2,3}{3,4,5},这样3就是一个割顶了,缩点的话是在遍历完邻接表之后,再判断low[u]==dfn[u],如此5个点就缩成了一个点,即一个分量,虽然这个分量包含奇数个点,输出同样是0,但与我们的思路是不一样的。实际情况是分成两个分量,每个分量有三个点,割顶3同时出现在两个分量中。然后想着改进,当把割顶弹出栈后,再弹入,搞啊搞,还是算了,学着白书上用边搞。

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<vector>
      4 #include<stack>
      5 #include<algorithm>
      6 using namespace std;
      7 
      8 const int MAXN=1111;
      9 
     10 struct EDGE{
     11     int u,v;
     12     EDGE(){}
     13     EDGE(int _u,int _v):u(_u),v(_v){}
     14 };
     15 
     16 struct Edge{
     17     int v,next;
     18     Edge(){}
     19     Edge(int _v,int _next):v(_v),next(_next){}
     20 }edge[MAXN*MAXN];
     21 
     22 int mp[MAXN][MAXN],tol,head[MAXN];
     23 int low[MAXN],dfn[MAXN],bccno[MAXN],iscut[MAXN],TT,bcc_cnt;
     24 int que[MAXN],color[MAXN];
     25 int sign[MAXN];
     26 
     27 vector<int >bcc[MAXN];
     28 stack<EDGE >stk;
     29 
     30 void init()
     31 {
     32     tol=0;
     33     memset(head,-1,sizeof(head));
     34 }
     35 
     36 void add(int u,int v)
     37 {
     38     edge[tol]=Edge(v,head[u]);
     39     head[u]=tol++;
     40 }
     41 
     42 void dfs(int u,int fa)
     43 {
     44     low[u]=dfn[u]=++TT;
     45     int son=0;
     46     for(int i=head[u];i!=-1;i=edge[i].next)
     47     {
     48         int v=edge[i].v;
     49         EDGE e=EDGE(u,v);
     50         if(!dfn[v]){
     51             stk.push(e);
     52             son++;
     53             dfs(v,u);
     54             low[u]=min(low[v],low[u]);
     55             if(low[v]>=low[u]){
     56                 iscut[u]=1;
     57                 bcc_cnt++;
     58                 bcc[bcc_cnt].clear();
     59                 while(1)
     60                 {
     61                     EDGE x=stk.top();
     62                     stk.pop();
     63                     if(bccno[x.u]!=bcc_cnt){
     64                         bcc[bcc_cnt].push_back(x.u);
     65                         bccno[x.u]=bcc_cnt;
     66                     }
     67                     if(bccno[x.v]!=bcc_cnt){
     68                         bcc[bcc_cnt].push_back(x.v);
     69                         bccno[x.v]=bcc_cnt;
     70                     }
     71                     if(x.u==u&&x.v==v)
     72                         break;
     73                 }
     74             }
     75         }else if(dfn[v]<dfn[u]&&v!=fa){
     76             stk.push(e);
     77             low[u]=min(low[u],dfn[v]);
     78         }
     79     }
     80     if(fa<0&&son==1)
     81         iscut[u]=0;
     82 }
     83 
     84 void find_bcc(int n)
     85 {
     86     memset(low,0,sizeof(low));
     87     memset(dfn,0,sizeof(dfn));
     88     memset(bccno,0,sizeof(bccno));
     89     memset(iscut,0,sizeof(iscut));
     90 
     91     TT=bcc_cnt=0;
     92 
     93     for(int i=1;i<=n;i++)
     94         if(!dfn[i])
     95             dfs(i,-1);
     96 }
     97 
     98 bool bfs(int x,int fa)
     99 {
    100     int l,r;
    101     l=r=0;
    102     que[r++]=x;
    103     while(l<r)
    104     {
    105         int u=que[l++];
    106         for(int i=head[u];i!=-1;i=edge[i].next)
    107         {
    108             int v=edge[i].v;
    109             if(bccno[v]!=fa)
    110                 continue ;
    111             if(color[v]==-1){
    112                 color[v]=color[u]^1;
    113                 que[r++]=v;
    114             }else if(color[v]==color[u])
    115                 return false;
    116         }
    117     }
    118     return true;
    119 }
    120 
    121 void Bjudge()
    122 {
    123     memset(sign,0,sizeof(sign));
    124     for(int i=1;i<=bcc_cnt;i++)
    125     {
    126         memset(color,-1,sizeof(color));
    127         for(int j=0;j<bcc[i].size();j++)
    128             bccno[bcc[i][j]]=i;
    129         int u=bcc[i][0];
    130         color[u]=0;
    131         if(!bfs(u,i)){
    132             for(int j=0;j<bcc[i].size();j++)
    133                 sign[bcc[i][j]]=1;
    134         }
    135     }
    136 }
    137 
    138 int main()
    139 {
    140     int n,m;
    141     int a,b;
    142     while(~scanf("%d%d",&n,&m)!=EOF)
    143     {
    144         if(!n&&!m)
    145             break;
    146         memset(mp,0,sizeof(mp));
    147         for(int i=0;i<m;i++)
    148         {
    149             scanf("%d%d",&a,&b);
    150             mp[a][b]=mp[b][a]=1;
    151         }
    152 
    153         init();
    154         for(int i=1;i<=n;i++)
    155         {
    156             for(int j=i+1;j<=n;j++)
    157             {
    158                 if(!mp[i][j]){
    159                     add(i,j);
    160                     add(j,i);
    161                 }
    162             }
    163         }
    164         
    165         find_bcc(n);
    166 
    167         Bjudge();
    168 
    169         int ans=0;
    170         for(int i=1;i<=n;i++)
    171             if(!sign[i])
    172                 ans++;
    173         printf("%d
    ",ans);
    174     }
    175     return 0;
    176 }
    177 /*
    178 5 4
    179 1 4
    180 1 5
    181 2 4
    182 2 5
    183 
    184 6 8
    185 1 4 1 5 1 6
    186 2 4 2 5 2 6
    187 3 4 3 5
    188 */
    View Code

    最近做了几道connectivity的题目,总结一下。

    关于割顶、桥、双连通、边双连通,以及强连通处理方式有其相似性,关键都与时间戳有关。

    其中,割顶->双连通 是low[v]>=dfn[u],桥->边双连通 是low[v]>dfn[u],只是一个等号的差别,其他处理基本相同;而强连通总是伴随着缩点 low[u]==dfn[u](这个一般是做边标记edge[].vis,这样即使是无向图也可以以edge[i^1].vis标记掉,而不影响重边的情况)。事实上,如果不考虑具体的桥,对边-双连通分量的划分就是在做无向图上的缩点操作。

    这三个判定条件的位置也有不同。缩点是在遍历完u的邻接表之后,用每个low[v]的值更新low[u],并且u本身不会连到祖先去(这一点很重要),则是一个环,可以缩掉;在无向图中,判断双连通分量,也就是割顶(边-双连通分量&桥 一样),是每遍历一个孩子v,就要判断:low[v]>=dfn[u],只要点u的孩子所能到达的最大值不超过u,那么u就是割顶(删除u后,该子树独立),当然,u的每一个孩子v都可以是被 割顶u 分离,注意u本身是可以与它的祖先连接的!!

  • 相关阅读:
    左孩子右兄弟的字典树
    UVA 1401 Remember the Word
    HDOJ 4770 Lights Against Dudely
    UvaLA 3938 "Ray, Pass me the dishes!"
    UVA
    Codeforces 215A A.Sereja and Coat Rack
    Codeforces 215B B.Sereja and Suffixes
    HDU 4788 Hard Disk Drive
    HDU 2095 find your present (2)
    图的连通性问题—学习笔记
  • 原文地址:https://www.cnblogs.com/zstu-abc/p/3234037.html
Copyright © 2011-2022 走看看