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本身是可以与它的祖先连接的!!

  • 相关阅读:
    ceph之image(转)
    CEPH集群RBD快照创建、恢复、删除、克隆(转)
    java操作ceph之rbd基本操作
    Kubernetes (1.6) 中的存储类及其动态供给
    Linux 网络编程详解九
    Linux 网络编程详解八
    Linux 网络编程详解七(并发僵尸进程处理)
    Linux 网络编程详解六(多进程服务器僵尸进程解决方案)
    Linux 网络编程详解五(TCP/IP协议粘包解决方案二)
    C语言 memset函数盲点
  • 原文地址:https://www.cnblogs.com/zstu-abc/p/3234037.html
Copyright © 2011-2022 走看看