zoukankan      html  css  js  c++  java
  • 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],这种情况其实已经不能再把那条边压到栈里了,因为这个环已经记录过了,不用再处理

  • 相关阅读:
    RN-Android构建失败:Caused by: org.gradle.api.ProjectConfigurationException: A problem occurred configuring root project 'AwesomeProject'.
    Android更新包下载成功后不出现安装界面
    真机调试: The application could not be installed: INSTALL_FAILED_TEST_ONLY
    react native 屏幕尺寸转换
    Android Studio生成签名文件,自动签名,以及获取SHA1和MD5值
    React Native安卓真机调试
    git提交代码报错Permission denied, please try again
    The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.
    命令行设置快捷命令
    Linux 常用指令
  • 原文地址:https://www.cnblogs.com/yijiull/p/7390246.html
Copyright © 2011-2022 走看看