zoukankan      html  css  js  c++  java
  • 蓝桥杯 试题 历届试题 危险系数 并查集/dfs

    问题描述

    抗日战争时期,冀中平原的地道战曾发挥重要作用。

    地道的多个站点间有通道连接,形成了庞大的网络。但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系。

    我们来定义一个危险系数DF(x,y):

    对于两个站点x和y (x != y), 如果能找到一个站点z,当z被敌人破坏后,x和y不连通,那么我们称z为关于x,y的关键点。相应的,对于任意一对站点x和y,危险系数DF(x,y)就表示为这两点之间的关键点个数。

    本题的任务是:已知网络结构,求两站点之间的危险系数。

    输入格式

    输入数据第一行包含2个整数n(2 <= n <= 1000), m(0 <= m <= 2000),分别代表站点数,通道数;

    接下来m行,每行两个整数 u,v (1 <= u, v <= n; u != v)代表一条通道;

    最后1行,两个数u,v,代表询问两点之间的危险系数DF(u, v)。

    输出格式
    一个整数,如果询问的两点不连通则输出-1.
    样例输入
    7 6
    1 3
    2 3
    3 4
    3 5
    4 5
    5 6
    1 6
    样例输出
    2
    解题思路:
    • 题目即求割点。因为并查集可以判断两点是否联通(类似于蓝桥杯发现环:https://www.cnblogs.com/w-like-code/p/12934398.html),所以一个思路是依次去掉通道,判断此时u,v是否联通,

    若不联通说明与此边的点为关键点。注意让避免重复计算某点,且要排除u,v。

    • 实现代码:
      1 #include<cstdio>
      2 
      3 const int Max_N = 1000;
      4 const int Max_M = 2000;
      5 
      6 int n,m;
      7 int U[Max_M],V[Max_M]; //保存通道两点 
      8 int u,v; //待查询 
      9 
     10 int par[Max_N+1];
     11 int rank[Max_N+1];
     12 
     13 bool used[Max_N+1];
     14 
     15 void init( int n )
     16 {
     17     for( int i=1; i<=n; i++ )
     18     {
     19         par[i] = i;
     20         rank[i] = 0;
     21     }
     22 }
     23 
     24 int find( int x )
     25 {
     26     if( par[x]==x ){
     27         return x;
     28     }
     29     return par[x] = find( par[x] );
     30 }
     31 
     32 void unite( int x, int y)
     33 {
     34     x = find(x); y = find(y);
     35     if( x==y ){
     36         return;
     37     }
     38     if( rank[x]<rank[y] ){
     39         par[x] = y;
     40     }
     41     else{
     42         par[y] = x;
     43         if( rank[x]==rank[y] ){
     44             rank[x]++;
     45         }
     46     }
     47 }
     48 
     49 bool same( int x, int y )
     50 {
     51     return find(x)==find(y);
     52 }
     53 
     54 void solve()
     55 {
     56     //首先判断u,v是否联通  
     57     init( n );
     58     for( int i=0; i<m; i++ ){
     59         unite( U[i],V[i] );
     60     }
     61     if( !same(u,v) ){  
     62         printf("-1
    ");
     63         return;
     64     }
     65     
     66     //每次判处下标为i的通道 用并查集判断关键点 
     67     int res = 0;
     68     for( int i=0; i<m; i++ )
     69     {
     70         init(n);
     71         for( int j=0; j<m; j++ )
     72         {
     73             if( i==j )    continue;
     74             
     75             unite(U[j],V[j]);
     76         }
     77         if( !same(u,v) ){
     78             if( !used[U[i]] ){ //用used[]避免重复计算 
     79                 res++;
     80                 used[U[i]] = true;
     81             }
     82             if( !used[V[i]] ){
     83                 res++;
     84                 used[V[i]] = true;
     85             }
     86         }
     87     }
     88     if( used[u] )    res--;
     89     if( used[v] )    res--;
     90     
     91     printf("%d
    ",res);
     92 }
     93 
     94 int main()
     95 {
     96     scanf("%d%d",&n,&m);
     97     for( int i=0; i<m; i++ )
     98     {
     99         scanf("%d%d",&U[i],&V[i]);
    100     }
    101     scanf("%d%d",&u,&v);
    102     
    103     solve();
    104     
    105     return 0;
    106 }
    View Code
    • 另一个思路是用dfs判断从u到v的所有路径,而关键点就是每个u到v路径都要经过的点。
    • 实现代码: 首先思路是若dfs到达v,返回true,所有返回true的节点都+1。但可能出现:
    • 对于五角星割点,其只有一次返回true,计数为1,但实际上u-v路径数为2

    • 错误代码: 

     1 #include<cstdio>
     2 #include<vector>
     3 using namespace std;
     4 
     5 const int Max_N = 1000;
     6 const int Max_M = 2000;
     7 
     8 //输入 
     9 int n,m;
    10 int u,v;
    11 vector<int> G[Max_N+1]; //
    12 
    13 bool visited[Max_N+1]; //visited[i]:在当前dfs()中是否访问过i 
    14 int count[Max_N+1]; //count[i]:下标i出现在u-v路径中的次数 
    15 int sum; //计算所有路径数 
    16  
    17 bool dfs( int x )
    18 {
    19     if( x==v ){
    20         sum++;
    21         return true;
    22     }
    23     
    24     bool flag = false;
    25     for( int i=0; i<G[x].size(); i++ )
    26     {
    27         int x_ = G[x][i];
    28         if( !visited[x_] )
    29         {
    30             visited[x_] = true;
    31             if( dfs( x_ ) ){
    32                 count[x]++;
    33                 flag = true;
    34             }
    35             visited[x_] = false;    
    36         } 
    37     }
    38     return flag;
    39 }
    40 
    41 void solve()
    42 {    
    43     
    44     visited[u] = true;
    45     if( !dfs( u ) ){//若u,v不连通 
    46         printf("-1
    ");
    47         return;
    48     }
    49     
    50     int res = 0;
    51     for( int i=1; i<=n; i++ )
    52     {
    53         if( count[i]==sum ){
    54             res++;
    55         }
    56     }
    57     
    58     if( count[u]==sum )    res--;//多记录了u 
    59     
    60     printf("%d
    ",res); 
    61 }
    62 
    63 int main()
    64 {
    65     scanf("%d%d",&n,&m);
    66     for( int i=0; i<m; i++ )
    67     {
    68         int x,y;
    69         scanf("%d%d",&x,&y);
    70         G[x].push_back(y); G[y].push_back(x);
    71     }
    72     scanf("%d%d",&u,&v);
    73     
    74     solve();
    75     
    76     return 0;
    77 }
    View Code
    • 只要用一个数组将经过节点保存,并记录数组长度,当到达v时把数组中节点计数即可。
    • 正确代码:
     1 #include<cstdio>
     2 #include<vector>
     3 using namespace std;
     4 
     5 const int Max_N = 1000;
     6 const int Max_M = 2000;
     7 
     8 //输入 
     9 int n,m;
    10 int u,v;
    11 vector<int> G[Max_N+1]; //
    12 
    13 bool visited[Max_N+1]; //visited[i]:在当前dfs()中是否访问过i 
    14 int count[Max_N+1]; //count[i]:下标i出现在u-v路径中的次数 
    15 int sum; //计算所有路径数 
    16 
    17 int way[Max_N]; //记录路径节点 
    18  
    19 void dfs( int x , int index )
    20 {
    21     if( x==v ){
    22         sum++;
    23         for( int i=0; i<index; i++ ){
    24             count[way[i]]++;
    25         }
    26         return;
    27     }
    28     
    29     way[index] = x;
    30     for( int i=0; i<G[x].size(); i++ )
    31     {
    32         int x_ = G[x][i];
    33         if( !visited[x_] )
    34         {
    35             visited[x_] = true;
    36             dfs( x_, index+1 );
    37             visited[x_] = false;    
    38         } 
    39     }
    40 }
    41 
    42 void solve()
    43 {    
    44     
    45     visited[u] = true;
    46     dfs( u , 0 );
    47     
    48     if( count[u]==0 ){
    49         printf("-1
    ");
    50         return;
    51     }
    52     
    53     int res = 0;
    54     for( int i=1; i<=n; i++ )
    55     {
    56         if( count[i]==sum ){
    57             res++;
    58         }
    59     }
    60     
    61     printf("%d
    ",res-1); //多记录了节点u 
    62 }
    63 
    64 int main()
    65 {
    66     scanf("%d%d",&n,&m);
    67     for( int i=0; i<m; i++ )
    68     {
    69         int x,y;
    70         scanf("%d%d",&x,&y);
    71         G[x].push_back(y); G[y].push_back(x);
    72     }
    73     scanf("%d%d",&u,&v);
    74     
    75     solve();
    76     
    77     return 0;
    78 }
    View Code
  • 相关阅读:
    分享50个漂亮的设计师个人作品集网站案例
    Jquery中$.get(),$.post(),$.ajax(),$.getJSON()的用法总结
    ajax异步请求
    angularJS(6)
    angularJS(5)
    PHP实现RTX发送消息提醒
    ajax异步请求
    angularJS(4)
    angularJS(3)
    jsPanel插件Option总结
  • 原文地址:https://www.cnblogs.com/w-like-code/p/13906390.html
Copyright © 2011-2022 走看看