前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >蓝桥杯 危险系数

蓝桥杯 危险系数

作者头像
用户1148523
发布2018-01-09 10:29:34
7350
发布2018-01-09 10:29:34
举报
文章被收录于专栏:Fish

题意就是求图中两点之间的割点的数目。

不知道被谁指导的说求割点可以用tarjan算法,就用了tarjan算法,但是tarjan算法求的是整个图的割点个数啊,至于用tarjan怎么求两点间的割点就不知道了。做了N多努力也是没求出来。然后就搜了题解,搜题解的时候遭受到大神碾压,某大神在blog里是这么说的“dfs,水题,秒过”TUT,然后痛定思痛决定看看大神怎么写的。具体思路就是,从开始点进行dfs,记录经过的路径,然后到了终点,就将路径里的点弄到另一个数组里,最后判断路径个数和点出现的次数是不是相等,如果相等就说明去掉这个点,任何路径都无法到达了。

代码语言:javascript
复制
#include<iostream>
#include<stdio.h>
#define N 1001
using namespace std;
typedef struct Edge {
	int v;
	struct Edge* next;
} Edge;
Edge Head[N];
int n,m;
int start,end;
bool visited[N];
int way[N];
int cp_count[N];
int way_count;
int cp_num;
bool flag[N];
void dfs(int v,int index) {
	flag[v]=1;
	visited[v]=1;
	//将该点存入路径中 
	way[index]=v;
	//如果这个点是终点 
	if(v==end) {
	//就将这个路径中所有点的次数加一 
		for(int i=0; i<=index; i++)
			cp_count[way[i]]++;
	//路径数也加一 
		way_count++;
	}
	for(Edge* i=Head[v].next; i; i=i->next)
		if(!visited[i->v]) {
			dfs(i->v,index+1);
			//这个比较重要,就是一定要把遍历过的点再弄成没有遍历的,因为下一个路径也有可能经过它 
			visited[i->v]=0;
		}
}

int main() {
	cin>>n>>m;
	for(int i=0; i<m; i++) {
		int x,y;
		cin>>x>>y;
		Edge *tp1,*tp2;
		tp1=new Edge;
		tp2=new Edge;
		tp1->v=y;
		tp1->next=Head[x].next;
		Head[x].next=tp1;
		tp2->v=x;
		tp2->next=Head[y].next;
		Head[y].next=tp2;
	}
	cin>>start>>end;
	dfs(start,0);
	//循环判断路径中的点的出现次数和路径个数 
	for(int i=1; i<=n; i++)
		if(cp_count[i]==way_count)
			cp_num++;
	//感觉这里有点笨了,用flag数组来标识从start点开始遍历过的点,如果从start开始 
	// 没有遍历过end说明这俩点就不连同 
	if(flag[end]==0) cout<<-1;
	else//这里减二是因为cp_num也把start和end算进来了 
		cout<<cp_num-2;

	return 0;
}

顺便贴上用tarjan算法记录图割点数量的代码,从错误中学到的东西总比成功要多。

代码语言:javascript
复制
#include<iostream>
#include<stdio.h>
#define N 1001
using namespace std;
typedef struct Edge {
	int v;
	struct Edge* next;
} Edge;
Edge Head[N];
int parent[N];
int low[N],dfn[N];
int count;
bool cutpoint[N];
bool flag;
int n,m;
int start,end;

void tarjan(int u) {
	int children=0;
	low[u]=dfn[u]=++count;
	for(Edge* i=Head[u].next; i; i=i->next) {
		int v=i->v;
		if(!dfn[v]) {
			children++;
			parent[v]=u;
			tarjan(v);
			low[u]=min(low[u],low[v]);
			//如果是父节点同时子树多于一个 ,那么这个点的父节点就是割点
			if(parent[u]==0 && children >1) cutpoint[u]=1;
			//如果是非父节点,同时这个点的最近祖先节点比其父节点靠后,那么它的父节点就是割点
			if(parent[u]!=0 && low[v]>=dfn[u])  cutpoint[u]=1;
		}//如果有回边,就是这个点指向的不是它的父节点而是它的祖先节点
		else if(v!=parent[u]) {
			low[u]=min(low[u],dfn[v]);
		}


	}
}

int main() {
	cin>>n>>m;
	for(int i=0; i<m; i++) {
		int x,y;
		cin>>x>>y;
		Edge *tp1,*tp2;
		tp1=new Edge;
		tp2=new Edge;
		tp1->v=y;
		tp1->next=Head[x].next;
		Head[x].next=tp1;
		tp2->v=x;
		tp2->next=Head[y].next;
		Head[y].next=tp2;
	}
	cin>>start>>end;
	//这是用tarjan算法求割点的个数,但是我觉得并不适合这个题
	tarjan(start);
	cutpoint[start]=0;
	cutpoint[end]=0;
	for(int i=1; i<=n; i++)
		if(cutpoint[i]) cp_num++;
	if(!dfn[end])
		cout<<-1;
	else
		cout<<cp_num;
	return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016年03月15日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档