[蓝桥杯][2013年第四届真题]危险系数

两种方法
(水平有限,看客自行参考,代码均可通过样例,但有些问题,欢迎指正)

题目描述

问题描述

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

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

我们来定义一个危险系数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

方法1
dfs用于判断两点在删除某点后是否依然联通,每次删除后都判断一次,由于遍历次数较多,采用了记忆深搜,降低了时间开销,但增大了空间开销(数据正确,仅内存超限,待改进)

#include<iostream>
#include<vector>
#include<list>
using  namespace std ;

vector<list<int>> vex;    //图,邻接表结构
vector<bool> visited;     //记录遍历过的点
vector<vector<vector<short int>>> ms;   //记忆搜索
bool dfs(int u,int v,int x){    //深搜,删除点x后,从u到v是否连通
    if(ms[u][v][x]!=-1) return ms[u][v][x];
    if(u==v)  return ms[u][v][x]=1;
    visited[u]=true;
    for(list<int>::iterator it=vex[u].begin();it!=vex[u].end();it++){
        if(*it==x) continue;
        if(!visited[*it])
            if(dfs(*it,v,x)) return ms[*it][v][x]=1;
    }
    return ms[u][v][x]=0;
}

int main(){
     int n,m;
     cin>>n>>m;
     vex.resize(n+1);
     int u,v;
     for(int i=1;i<=m;i++){
        cin>>u>>v;
        vex[u].push_back(v);
        vex[v].push_back(u);
     }
     cin>>u>>v;        //以上为输入部分
     int sum=0;   //关键点数
     ms.resize(n+1);
     for(int i=1;i<=n;i++) ms[i].resize(n+1);
     for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        ms[i][j].assign(n,-1);     //初始化ms,-1表示未深搜的状态
     visited.assign(n,0);    //初始化visited为0
     if(!dfs(u,v,0)){    //如果不通,直接输出-1
        cout<<-1;
        return 0;
     }
     for(int i=1;i<=n;i++){      //逐个点删除后看是否依然连通
        if(i==u||i==v)  continue;
        visited.assign(n,0);
        if(!dfs(u,v,i))  sum++;
     }
     cout<<sum;
     return 0;
 }

方法2
在之前的基础上修改。DFS用于遍历两点的所有路径。不用多次遍历。
统计每条可以连通两点的路径,把每条路径上的点的标记加1,最后点的标记数等于路径数的即为关键点。

#include<iostream>
#include<vector>
#include<list>
#include<stack>
using  namespace std ;

vector<list<int>> vex;
vector<bool> visited;
vector<vector<vector<short int>>> ms;
stack<int> path;
vector<int> pointNumInPath;  //点的标记,代表参与的路径数
int pathNum=0,keyPointNum=0;   //路径数,关键点数

//bool dfs(int u,int v,int x){
//    if(ms[u][v][x]!=-1) return ms[u][v][x];
//    if(u==v)  return ms[u][v][x]=1;
//    visited[u]=true;
//    for(list<int>::iterator it=vex[u].begin();it!=vex[u].end();it++){
//        if(*it==x) continue;
//        if(!visited[*it])
//            if(dfs(*it,v,x)) return ms[*it][v][x]=1;
//    }
//    return ms[u][v][x]=0;
//}
//
//void printPath(){     //打印路径
//    stack<int> temp;
//    int n=path.size();
//    for(int i=0;i<n;i++){
//        temp.push(path.top());
//        path.pop();
//    }
//    for(int i=0;i<n;i++){
//        cout<<temp.top()<<" ";
//        path.push(temp.top());
//        temp.pop();
//    }
//    cout<<endl;
//}
void pointNum(){   //把路径上的点的标记加一
    stack<int> temp;
    int n=path.size();
    for(int i=0;i<n;i++){
        temp.push(path.top());
        path.pop();
    }
    for(int i=0;i<n;i++){
        pointNumInPath[temp.top()]++;
        path.push(temp.top());
        temp.pop();
    }
}
void DFS(int u,int v){    //遍历所有连通u,v两点的路径
    if(u==v){
        path.push(u);
//        printPath();
        pathNum++;
        pointNum();
        return;
    }
    path.push(u);
    visited[u]=true;
    for(list<int>::iterator it=vex[u].begin();it!=vex[u].end();it++){
        if(!visited[*it]){
            DFS(*it,v);
            path.pop();
            visited[*it]=false;
        }
    }
}
int main(){
     int n,m;
     cin>>n>>m;
     vex.resize(n+1);
     int u,v;
     for(int i=1;i<=m;i++){
        cin>>u>>v;
        vex[u].push_back(v);
        vex[v].push_back(u);
     }
     cin>>u>>v;
     visited.assign(n,0);
     pointNumInPath.assign(n,0);
     DFS(u,v);
     if(pathNum==0){
        cout<<-1;
        return 0;
     }
     for(int n:pointNumInPath){     //统计关键点
        if(n==pathNum) keyPointNum++;
     }
     cout<<keyPointNum-2;   //减去两个端点
     return 0;
 }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值