• Knights of the Round Table UVALive


    Knights of the Round Table

     UVALive - 3523

    题意:n个人开会,有些人相互憎恨不能挨着坐,且每场会议要保证是奇数个人。问有几个人一场会议也不能参加。

    【无向图的点的双连通分量+二分图的判定】

    不相互憎恨的人连边建图。

    题目本质上要求的是不在任何一个奇圈上的人有几个

    先求出所有的点双连通分量,如果该分量不是二分图说明有奇圈,有奇圈就说明每个人都可以参加至少一场会议(p317有证明,不难),把这些人标记,最后拿总人数减去这些人就是答案了。

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 const int maxv=1010;
      4 const int maxe=1000010;
      5 
      6 int n,m;
      7 
      8 int g[maxv][maxv];
      9 struct Edge{
     10     int u,v,nex;
     11 }e[maxe<<1];
     12 int head[maxv];
     13 int cnt=0;
     14 void add(int u,int v){
     15     e[cnt].u=u;
     16     e[cnt].v=v;
     17     e[cnt].nex=head[u];
     18     head[u]=cnt++;
     19 }
     20 void init(){
     21     memset(g,0,sizeof(g));
     22     memset(head,-1,sizeof(head));
     23     cnt=0;
     24 }
     25 
     26 int pre[maxv],iscut[maxv],bccno[maxv],dfsk,bcc_cnt;
     27 vector<int> bcc[maxv];
     28 stack<int> s;
     29 
     30 int dfs(int u,int f){
     31     int lowu=pre[u]=++dfsk;
     32     int child=0;
     33     for(int i=head[u];i!=-1;i=e[i].nex){
     34         int v=e[i].v;
     35         if(!pre[v]){
     36             s.push(i);
     37             child++;
     38             int lowv=dfs(v,u);
     39             lowu=min(lowu,lowv);
     40             if(lowv>=pre[u]){
     41                 iscut[u]=1;
     42                 bcc_cnt++;
     43                 bcc[bcc_cnt].clear(); //bcc从1开始编号
     44                 for(;;){
     45                     int te=s.top();
     46                     s.pop();
     47                     Edge p=e[te];
     48                     if(bccno[p.u]!=bcc_cnt) {bcc[bcc_cnt].push_back(p.u);bccno[p.u]=bcc_cnt; }
     49                     if(bccno[p.v]!=bcc_cnt) {bcc[bcc_cnt].push_back(p.v);bccno[p.v]=bcc_cnt; }
     50                     if(p.u==u&&p.v==v) break;
     51                 }
     52             }
     53         }else if(pre[v]<pre[u]&&v!=f){
     54             s.push(i);
     55             lowu=min(lowu,pre[v]);
     56         }
     57     }
     58     if(f<0&&child==1) iscut[u]=0;
     59     return lowu;
     60 }
     61 
     62 void find_bcc(int n)
     63 {
     64     memset(pre,0,sizeof(pre));
     65     memset(iscut,0,sizeof(iscut));
     66     memset(bccno,0,sizeof(bccno));
     67     dfsk=bcc_cnt=0;
     68     for(int i=0;i<n;i++) if(!pre[i])
     69         dfs(i,-1);
     70 }
     71 
     72 int odd[maxv];  //是否可以参加会议
     73 int color[maxv];
     74 bool bipartite(int u,int b){
     75     for(int i=head[u];i!=-1;i=e[i].nex){
     76         int v=e[i].v;
     77         if(bccno[v]!=b) continue;
     78         if(color[u]==color[v]) return false;
     79         if(!color[v]){
     80             color[v]=3-color[u];
     81             if(!bipartite(v,b)) return false;
     82         }
     83     }
     84     return true;
     85 }
     86 int main(){
     87     while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){
     88         init();
     89         int u,v;
     90         for(int i=0;i<m;i++){
     91             scanf("%d%d",&u,&v);
     92             u--;v--;
     93             g[u][v]=g[v][u]=1;
     94         }
     95         for(int i=0;i<n;i++)
     96             for(int j=i+1;j<n;j++) if(!g[i][j]){
     97                 add(i,j);
     98                 add(j,i);
     99             }
    100         find_bcc(n);
    101         
    102         memset(odd,0,sizeof(odd));
    103         for(int i=1;i<=bcc_cnt;i++){
    104             memset(color,0,sizeof(color));
    105             for(int j=0;j<bcc[i].size();j++) bccno[bcc[i][j]]=i; //这一步是因为可能有的点属于不止一个点双连通分量
    106             int u=bcc[i][0];
    107             color[u]=1;
    108             if(!bipartite(u,i)) 
    109                 for(int j=0;j<bcc[i].size();j++) odd[bcc[i][j]]=1;
    110         }
    111         int ans=n;
    112         for(int i=0;i<n;i++) if(odd[i]) ans--;
    113         printf("%d
    ",ans);
    114     }
    115     return 0;
    116 }
    View Code

      下面这份代码有问题,,注释里写了

      1 #include <iostream>
      2 #include <cstring>
      3 #include <stack>
      4 #include <vector>
      5 #include <cstdio>
      6 using namespace std;
      7 const int maxv=1010;
      8 int A[maxv][maxv];
      9 int n,m;
     10 struct Edge
     11 {
     12     int u,v,nex;
     13 }e[maxv*maxv<<1];
     14 int head[maxv];
     15 int cnt=0;
     16 void init()
     17 {
     18     memset(head,-1,sizeof(head));
     19     cnt=0;
     20 }
     21 void add(int u,int v)
     22 {
     23     e[cnt].u=u;
     24     e[cnt].v=v;
     25     e[cnt].nex=head[u];
     26     head[u]=cnt++;
     27 }
     28 
     29 int pre[maxv],iscut[maxv],bccno[maxv],dfsk,bcc_cnt;
     30 stack<int> s;
     31 vector<int> bcc[maxv];
     32 
     33 int dfs(int u,int id)
     34 {
     35     int lowu=pre[u]=++dfsk;
     36     int child=0;
     37     for(int i=head[u];i!=-1;i=e[i].nex)
     38     {
     39         int v=e[i].v;
     40         if(i==(id^1)) continue;
     41         if(!pre[v])
     42         {
     43             child++;
     44             s.push(i);
     45             int lowv=dfs(v,id);
     46             lowu=min(lowv,lowu);
     47             if(lowv>=pre[u])  // 说明u是割顶
     48             {
     49                 iscut[u]=1;
     50                 bcc_cnt++;
     51                 bcc[bcc_cnt].clear();
     52                 for(;;)
     53                 {
     54                     Edge p=e[s.top()];
     55                     s.pop();
     56                     if(bccno[p.u]!=bcc_cnt) {bcc[bcc_cnt].push_back(p.u);bccno[p.u]=bcc_cnt;}
     57                     if(bccno[p.v]!=bcc_cnt) {bcc[bcc_cnt].push_back(p.v);bccno[p.v]=bcc_cnt;}
     58                     if(p.v==v&&p.u==u) break;
     59                 }
     60             }
     61         }
     62         else   if(pre[v]<pre[u])   //不加这一句就会错,,无解。。pre[v]难道不是一定小于pre[u]吗??
     63         {
     64             s.push(i);
     65             lowu=min(lowu,pre[v]);
     66         }
     67     }
     68     if(id<0&&child==1) iscut[u]=0;
     69     return lowu;
     70 }
     71 
     72 void find_bcc(int n)
     73 {
     74     memset(pre,0,sizeof(pre));
     75     memset(bccno,0,sizeof(bccno));
     76     memset(iscut,0,sizeof(iscut));
     77     dfsk=bcc_cnt=0;
     78     for(int i=0;i<n;i++) if(!pre[i]) dfs(i,-1);
     79 }
     80 int odd[maxv],color[maxv];
     81 int bigraph(int u,int b)
     82 {
     83     for(int i=head[u];i!=-1;i=e[i].nex)
     84     {
     85         int v=e[i].v;
     86         if(bccno[v]!=b) continue;
     87         if(color[v]==color[u]) return 0;
     88         if(!color[v])
     89         {
     90             color[v]=3-color[u];
     91             if(!bigraph(v,b)) return 0;
     92         }
     93     }
     94     return 1;
     95 }
     96 int main()
     97 {
     98     while(scanf("%d%d",&n,&m)&&(n||m))
     99     {
    100         init();
    101         int u,v;
    102         memset(A,0,sizeof(A));
    103         for(int i=0;i<m;i++)
    104         {
    105             scanf("%d%d",&u,&v);
    106             u--;v--;
    107             A[u][v]=A[v][u]=1;
    108         }
    109         for(int i=0;i<n;i++)
    110             for(int j=i+1;j<n;j++) if(!A[i][j])
    111             {
    112                 add(i,j);
    113                 add(j,i);
    114             }
    115 
    116         find_bcc(n);
    117 
    118         memset(odd,0,sizeof(odd));
    119         for(int i=1;i<=bcc_cnt;i++)
    120         {
    121             memset(color,0,sizeof(color));
    122             for(int j=0;j<bcc[i].size();j++) bccno[bcc[i][j]]=i;  //有可能某个点属于多个环
    123             int u=bcc[i][0];
    124             color[u]=1;
    125             if(!bigraph(u,i))  //不是二分图----有奇环----都可参加至少一次会议
    126                 for(int j=0;j<bcc[i].size();j++) odd[bcc[i][j]]=1;
    127         }
    128         int ans=n;
    129         for(int i=0;i<n;i++)
    130             if(odd[i]) ans--;
    131         printf("%d
    ",ans);
    132     }
    133 }
    View Code

    问题解决了,,pre[v]不一定小于pre[u],

    在一个环里,如果顺时针dfs的话,最后会有pre[v]<pre[u],然后倒推回去会把这个环加到同一个新的连通分量里

    接下来,按dfs接着走,会逆时针再去访问这个环,这时候会有pre[v]>pre[u],这种情况其实已经不能再把那条边压到栈里了,因为这个环已经记录过了,不用再处理

  • 相关阅读:
    string 流
    文件输入和输出
    IO类
    算法
    MySQL常用处理方法
    linux curl工具
    设计模式
    C语言编程流程
    js escape 与php escape
    js undefined易错分析
  • 原文地址:https://www.cnblogs.com/yijiull/p/7390246.html
Copyright © 2020-2023  润新知