P8604 [蓝桥杯 2013 国 C] 危险系数(DFS)

 题目传送门

 题目大意:

给定一个无向图,给定起点和终点,问有多少个点删去之后使得起点和终点不连通,如果起点和终点本身不连通则输出-1

第一思路:直接按照题目所说模拟该过程即可,先判断图中起点和终点是否连通,如果不连通直接输出-1,否则循环所有的边,每次去掉一条边之后进行dfs,如果去掉边之后不连通了,说明该边为关键边,则计数,反之不是关键边 

下面代码无法通过所有样例,但思路是正确的

#include<iostream>
#include<vector>
#define int long long

using namespace std;

vector<int>edges[1005];//临接表存储图
vector<bool>visited(1005);//记录是否走过
vector<pair<int, int> >temp;//记录所有边
int n, m, start, endd, ans = 0, sum = 0;
bool sign = false;

void dfs(int cur) {
	if (cur == endd) {
		sign = true;
	}
	else {
		int len = edges[cur].size();
		for (int i = 0; i < len; i++) {
			int value = edges[cur][i];
			if (!visited[value]&&value!=0) {
				visited[value] = 1;
				dfs(value);
				visited[value] = 0;
			}
		}
	}
}


signed main()
{
	cin >> n >> m;
	int v1, v2,len;
	for (int i = 0; i < m; i++) {
		cin >> v1 >> v2;
		temp.push_back({ v1,v2 });
		edges[v1].push_back(v2);
		edges[v2].push_back(v1);
	}
	cin >> start >> endd;
	//先确定起点和终点可以连通
	visited[start] = 1;
	dfs(start);
	if (!sign) {
		cout << "-1" << endl;
		return 0;
	}
	visited[start] = 0;

	//每次去掉一条边之后从起点开始dfs看能不能到目的地,不能则是关键边,反之不是
	len = temp.size();
	int index1, index2;
	for (int i = 0; i < len; i++) {//遍历每条边
		sign = false;
		v1 = temp[i].first;
		v2 = temp[i].second;
		int len2 = edges[v1].size();
		for (int j = 0; j < len2; j++) {
			if (edges[v1][j] == v2) {
				edges[v1][j] = 0;//暂时给0
				index1 = j;
			}
		}
		len2 = edges[v2].size();
		for (int j = 0; j < len2; j++) {
			if (edges[v2][j] == v1) {
				edges[v2][j] = 0;
				index2 = j;
			}
		}
		dfs(start);
		if (!sign) {
			ans++;
		}
		edges[v1][index1] = v2;
		edges[v2][index2] = v1;//恢复原状
	}
	cout << ans << endl;
	return 0;
}

 第二思路:很明显,如果某一条边是关键边的话,那么它肯定是我们从起点到终点的必经之路,所以我们在进行一次dfs的过程中,对起点和终点的路径总数进行计数,每当我们完成一次路径的行走后,对已经走过的点的行走次数进行计数,最后如果某个点经过次数与路径总数相等(即必经之路),那么我们判断它是关键点(这里因为起点和终点也会必经,所以最后需要减去2),最后输出关键点数量即可

#include<iostream>
#include<vector>
#define int long long

using namespace std;

vector<int>edges[1010];//临接表存储图
vector<bool>visited(1010);//记录是否走过
vector<int>vexnum(1010);//记录每个点走过次数
int n, m, start, endd, ans = 0, sum = 0;

void dfs(int cur) {
	if (cur == endd) {
		sum++;//路径总数
		for (int i = 1; i <= n; i++) {
			if (visited[i]==1) {
				vexnum[i]++;//每个点走过次数
			}
		}
	}
	else {
		int len = edges[cur].size();
		for (int i = 0; i < len; i++) {
			int value = edges[cur][i];
			if (!visited[value]) {
				visited[value] = 1;
				dfs(value);
				visited[value] = 0;
			}
		}
	}
}


signed main()
{
	cin >> n >> m;
	int v1, v2, len;
	for (int i = 0; i < m; i++) {
		cin >> v1 >> v2;
		edges[v1].push_back(v2);
		edges[v2].push_back(v1);
	}
	cin >> start >> endd;
	visited[start] = 1;
	dfs(start);
	if (sum > 0) {
		for (int i = 1; i <= n; i++) {
			if (vexnum[i] == sum) {//是否存在点走过次数与路径总数相等的点
				ans++;//关键点计数
			}
		}
		cout << ans - 2 << endl;//减2是因为统计时多加了起点和终点
	}
	else {
		cout << "-1" << endl;
	}
	return 0;
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZZZWWWFFF_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值