zoukankan      html  css  js  c++  java
  • BZOJ2730 矿场搭建 解题报告 点双联通分量

    题意概述:

      一张有向图,在其中设置一些关键点(即题目中的逃生出口),使得删除任意一个点之后其余点都可以到达至少一个关键点。

      问至少需要设置多少中关键点,有多少种设置方法。

    解析:

      首先,这道题要求删掉一个点,不难想到这道题与割点有关。其次,删掉一个点其他点仍然可以到达关键点就可以想到是点双联通分量。

      但是,问题关键是,真的需要在每一个点双联通分量中都设置一个关键点吗?

      

    答案是否定的,因为如果一个双联通分量连接了两个或两个以上的割点,一个割点被删掉那么还可以通过另外的割点到达某个关键点,如上图,红色点为割点,灰底色的边为割边

    所以只需统计含割点个数小于等于1的块数就是最少的关键点个数,如此,则放置关键点的方案数为各个被统计的块(割点数小于等于1的块)的点的个数的乘积,当然,若只找到了一个满足条件的块,那最少关键点数为2,方案数为(令n为点的个数):  n*(n-1)/2.

    需要注意的是这道题的数据规模:有500条边,但是并没有对点的编号的说明,所以点的标号可以是任意的,故此题建议离散化,但是我还是偷了个懒,因为数据中的点好像不超过50000

    代码如下:

      1 #include <iostream>
      2 #include <algorithm>
      3 #include <cstdio>
      4 #include <cstring>
      5 #include <cstdlib>
      6 #include <cmath>
      7 #include <ctime>
      8 #include <vector>
      9 
     10 using namespace std;
     11 
     12 //#define    File
     13 //#define    Debug
     14 
     15 struct Edge
     16 {
     17     int    to;
     18     int    next;
     19 }e[2100];
     20 
     21 int    n,cnt,cnt_blocks,bcc_cnt,top,Ans,kase;
     22 int    p[51000],dfn[51000],nbcc[51000];
     23 
     24 long long    Sum;
     25 
     26 pair<int,int>    st[51000];
     27 vector<int>    bcc[1100];
     28 
     29 bool    cut[51000];
     30 
     31 inline    void    Add_edge(const int x,const int y)
     32 {
     33     e[++cnt].to=y;
     34     e[cnt].next=p[x];
     35     p[x]=cnt;
     36     return ;
     37 }
     38 
     39 int    Tarjan(const int S,const int fa)
     40 {
     41     int    child,lowu,lowv,v,i;
     42 
     43     dfn[S]=lowu=++cnt_blocks;
     44     child=0;
     45     
     46     for(i=p[S];i;i=e[i].next)
     47     {
     48         v=e[i].to;
     49         if(!dfn[v])
     50         {
     51             st[++top]=make_pair(S,v);
     52             child++;
     53             lowv=Tarjan(v,S);
     54             lowu=min(lowv,lowu);
     55             if(lowv>=dfn[S])
     56             {
     57                 cut[S]=true;
     58                 bcc_cnt++;
     59                 bcc[bcc_cnt].clear();
     60                 while(true)
     61                 {
     62                     if(nbcc[st[top].first]!=bcc_cnt)
     63                     {
     64                         bcc[bcc_cnt].push_back(st[top].first);
     65                         nbcc[st[top].first]=bcc_cnt;
     66                     }
     67                     if(nbcc[st[top].second]!=bcc_cnt)
     68                     {
     69                         bcc[bcc_cnt].push_back(st[top].second);
     70                         nbcc[st[top].second]=bcc_cnt;
     71                     }
     72                     
     73                     if(st[top].first==S && st[top].second==v)
     74                         {top--;break;}
     75                     top--;
     76                 }
     77             }
     78         }
     79         else if(dfn[v]<dfn[S]  && v!=fa)
     80         {
     81             st[++top]=make_pair(S,e[i].to);
     82             lowu=min(lowu,dfn[v]);
     83         }
     84     }
     85 
     86     if(fa<0 && child==1)cut[S]=false;
     87     return lowu;
     88 }
     89 
     90 inline    void    Init()
     91 {
     92 /*int    n,cnt,cnt_blocks,bcc_cnt,top,Ans,kase;
     93 int    p[51000],dfn[51000],nbcc[51000];
     94 
     95 long long    Sum;
     96 
     97 pair<int,int>    st[51000];
     98 vector<int>    bcc[1100];
     99 
    100 bool    visited[51000],cut[51000];*/
    101     cnt=cnt_blocks=bcc_cnt=top=Ans=0;
    102     Sum=1;
    103     memset(p,0,sizeof(p));
    104     memset(dfn,0,sizeof(dfn));
    105     memset(nbcc,0,sizeof(nbcc));
    106     memset(cut,0,sizeof(cut));
    107     for(int i=1;i<=1000;++i)
    108         bcc[i].clear();
    109     memset(st,0,sizeof(st));
    110     return ;
    111 }
    112 
    113 
    114 int main()
    115 {
    116 #ifdef    File
    117     freopen("2730.in","r",stdin);
    118 #ifndef    Debug
    119     freopen("2730.out","w",stdout);
    120 #endif
    121 #endif
    122 
    123     int    i,j,x,y,cut_cnt;
    124 
    125     while(~scanf("%d",&n) && n)
    126     {
    127         Init();
    128         for(i=1;i<=n;++i)
    129         {
    130             scanf("%d%d",&x,&y);
    131             Add_edge(x,y);
    132             Add_edge(y,x);
    133         }
    134 
    135         for(i=1;i<=n;++i)
    136         {
    137             if(!dfn[i])Tarjan(i,-1);
    138         }
    139 
    140         for(i=1;i<=bcc_cnt;++i)
    141         {
    142             cut_cnt=0;
    143             for(j=0;j<(int)bcc[i].size();++j)
    144             {
    145                 if(cut[bcc[i][j]])cut_cnt++;
    146             }
    147             if(cut_cnt==1)
    148             {
    149                 Ans++;
    150                 Sum*=(long long)(bcc[i].size()-cut_cnt);
    151             }
    152         }
    153 
    154         if(bcc_cnt==1)
    155         {
    156             Ans=2;
    157             Sum=bcc[1].size()*(bcc[1].size()-1)/2;
    158         }
    159 
    160         printf("Case %d: %d %lld
    ",++kase,Ans,Sum);
    161     }
    162 
    163 #ifdef    File
    164     fclose(stdin);
    165 #ifndef    Debug
    166     fclose(stdout);
    167 #endif
    168 #endif
    169 
    170     return 0;
    171 }
    View Code
  • 相关阅读:
    序列化
    cookie 和 session
    a 标签提交表单
    SpringBoot使用Easypoi导出excel示例
    PDF操作类库 iText
    HandlerInterceptor
    Fastdfs
    InitializingBean
    CORS CorsFilter
    XMLHttpRequest
  • 原文地址:https://www.cnblogs.com/Gster/p/4813156.html
Copyright © 2011-2022 走看看