zoukankan      html  css  js  c++  java
  • 危险系数 蓝桥杯 求两点间割点 tarjan && poj 1523 SPF Apare_xzc

    危险系数 蓝桥杯 求两点间割点 tarjan && poj 1523

    题面

    问题描述
    抗日战争时期,冀中平原的地道战曾发挥重要作用。
    
    地道的多个站点间有通道连接,形成了庞大的网络。但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系。
    
    我们来定义一个危险系数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
    

    分析

    求两点之间的割点

    于是我就去学了一下tarjan算法

    推荐几篇博客:
    http://keyblog.cn/article-80.html
    https://www.cnblogs.com/mxrmxr/p/9715579.html


    学了tarjan算法之后去做了一下POJ 1523(割点模板题)

    题目链接

    题意:

    给一个无向图,求出所有割点以及去电每个割点后整个图连通分量增加的个数

    直接上代码好了:

    /*
     POJ 1523 SPF 求割点和每个割点去掉后增加的连通分量的个数 
    Run ID	   User	   Problem	Result	  Memory	Time	Language  Code Length	Submit Time
    21061713   apare   1523	    Accepted  164K	    0MS	    C++	1     476B	        2019-11-17 09:41:21
    */
    #include <iostream>
    #include <cstdio>
    #include <map>
    #include <cstring>
    using namespace std;
    const int maxn = 1000+50;
    const int maxm = 1000000+100;
    int head[maxn],tot,cnt;
    struct Node{
    	int to,Next;
    }node[maxm*2];
    int dfn[maxn],low[maxn];
    void init()
    {
    	tot = 0,cnt=0;
    	memset(dfn,0,sizeof(dfn));
    	memset(head,-1,sizeof(head));
    }
    void addedge(int from,int to)
    {
    	node[tot].to = to;
    	node[tot].Next = head[from];
    	head[from] = tot++;
    } 
    int ca;                        
    map<int,int> mp;
    map<int,int>::iterator it;
    void tarjan(int x,int root,int fa)
    {
    	dfn[x] = low[x] = ++cnt;
    	int child = 0;
    	for(int i=head[x];i!=-1;i=node[i].Next)
    	{
    		int to = node[i].to;
    		if(!dfn[to]) //这个节点to还没被访问过 
    		{
    			++child;
    			tarjan(to,root,x);
    			low[x] = min(low[x],low[to]);
    			if(x!=root&&dfn[x]<=low[to]) 
    				++mp[x]; 
    		}
    		else if(to!=fa) //这个节点已经被访问过了,而且不是父节点 
    		{
    			low[x] = min(low[x],dfn[to]);
    		} 
    	}
    	if(x==root&&child>=2) mp[x] = child-1;
    }
    void solve()
    {
    	mp.clear();
    	memset(dfn,0,sizeof(dfn));
    	tarjan(1,1,1);
    	printf("Network #%d
    ",++ca);
    	if(!mp.size())
    	{ 
    		printf("  No SPF nodes
    
    ");
    		return;
    	}
    	for(it=mp.begin();it!=mp.end();++it)                   
    		printf("  SPF node %d leaves %d subnets
    ",it->first,it->second+1);
    	printf("
    "); 
    }
    int main()
    {
    	int u,v=10;
    	init();
    	while(scanf("%d",&u)!=EOF)
    	{
    		if(u==0)
    		{
    			if(v==0) break;
    			solve();
    			init();
    		}
    		else
    		{
    			scanf("%d",&v);
    			addedge(u,v);
    			addedge(v,u);		
    		}	
    		v = u;
    	}
    	
    	return 0;
    }
    

    会了tarjan算法以后我们再来看危险系数这道题

    题意:求无向图中给定两点之间的割点数

    ps:参考了网上几乎所有博客,大多位dfs暴力枚举或者暴力并查集
      主要参考这篇文章

    思路:

    • 先找出图的所有割点,然后分别判断是否满足为两点st,ed的割点
    • 一个点是两点间的割点要满足几个条件:
    1. 该点可达ed
    2. 至少一个子节点可达ed回不去更早的节点

    代码:

    /*
    危险系数 xzc
    给定一个图,求两个点之间割点的个数 
    许智超	危险系数	11-18 17:16	1.665KB	C++	正确	100	0ms	16.23MB
    */
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1000+50;
    const int maxm = 2000000+50;
    int head[maxn],tot,st,ed;
    int cnt,dfn[maxn],low[maxn];
    bool reachEd[maxn];
    set<int> ans;
    set<int>::iterator it;
    struct Node{
    	int to,Next;
    }node[maxm];
    void initEdge()
    {
    	tot = 0;
    	memset(head,-1,sizeof(head));
    }
    void addedge(int from,int to)
    {
    	node[tot].to = to;
    	node[tot].Next = head[from];
    	head[from] = tot++;
    }
    void init()
    {
    	cnt = 0;
    	memset(dfn,0,sizeof(dfn));
    	memset(reachEd,false,sizeof(reachEd));
    	ans.clear();
    }
    void tarjan(int x,int root,int fa_x)
    {
    	dfn[x] = low[x] = ++cnt;
    	int child = 0;
    	for(int i=head[x];i!=-1;i=node[i].Next)
    	{
    		int to = node[i].to;
    		if(!dfn[to])
    		{
    			++child;
    			tarjan(to,root,x);
    			low[x] = min(low[x],low[to]);
    			if(to==ed||reachEd[to]) reachEd[x] = true;
    			if(x==root&&child>=2) ans.insert(x);
    			if(x!=root&&low[to]>=dfn[x]) ans.insert(x);
    		}
    		else if(to!=fa_x)
    		{
    			low[x] = min(low[x],dfn[to]);
    		}
    	}
    }
    int main()
    {	
    	int m,n,u,v,ca=0;
    	while(cin>>n>>m)
    	{
    		initEdge();
    		for(int i=0;i<m;++i)
    		{
    			scanf("%d%d",&u,&v);
    			addedge(u,v);
    			addedge(v,u);
    		}
    		scanf("%d%d",&st,&ed);
    		if(ca++)
    		{
    			init();
    		}
    		tarjan(st,st,st);
    		reachEd[ed] = true;
    		int res = 0;
    		for(it=ans.begin();it!=ans.end();++it)
    		{
    			int x = *it;
    			if(x==ed||x==st||!reachEd[x]) continue; //起点和终点都不算两点之间的割点 
    			int add = 0;
    			for(int i=head[x];i!=-1;i=node[i].Next)
    			{
    				int to = node[i].to;
    				if(low[to]>=dfn[x]&&reachEd[to])
    				{
    					add = 1;break;
    				}
    			}
    			res += add;
    		}
    		printf("%d
    ",res);
    	}
    	
    	
    	return 0;
    }
    
  • 相关阅读:
    添加yum源
    tar命令
    tomcat压力测试、优化
    vi命令
    Linux简单命令
    Linux简单命令
    vi命令
    tomcat压力测试、优化
    tar命令
    动态加载 CSS 文件
  • 原文地址:https://www.cnblogs.com/Apare-xzc/p/12243639.html
Copyright © 2011-2022 走看看