zoukankan      html  css  js  c++  java
  • Doves and bombs UVA

    //桥:删掉之后,图就不连通
    //边双连通分量:极大的不含有桥的连通块
    //不管删掉哪条边,都是连通的
    //任意两个点之间,至少存在两条不相交的路径
    
    //割点:如果把某个点和它所关联的所有边都删掉,图就不连通
    //每一个割点至少属于两个双连通分量
    //点双连通分量:极大的不包含割点的连通块
    
    //两个割点之间的边,不一定是桥
    //一个桥的两个端点,不一定是桥
    //边双连通分量不一定是点双连通分量
    //点双连通分量不一定是边双连通分量
    
    //找桥:x->y是桥 等价于 dfs(x)<low(y)
    //找遍双连通分量:做法1:将所有桥删掉,
    //				  做法2:用一个栈,搜索完dfs(x)==low(x),那么当前还在栈中的其他点,就是双连通分量的其他点
    
    //x--y
    //如何判断是不是割点:当low(y)>=dfn(x),
    //						1.如果x不是根节点,那么x就是割点 ,
    //						2.如果x是根节点,那么至少存在两个y,low(y)>=dfn(x)
    //如何求点的双连通分量:
    //
    
    
    
    //统计所有连通块个数cnt
    //依此枚举从哪个块中删,删哪个点,可以把当前块儿分成s部分
    //那么答案就是s+cnt-1的最大值
    //那么就是找s
    //用类似求割点的方法来做:
    //如果dfn(x)<=low(y),那么如果把x删掉,y就会单独出来,那么就会多一个单独的子树,多一个块儿
    //特判:如果x不是根节点,删掉之后就会有三部分(一般情况);如果是,删掉之后就会有两部分
    //也就是枚举删除哪个割点
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int N = 10050;
    int n, m;
    int h[N], e[N<<3], ne[N<<3], idx;
    int dfn[N], low[N], timestamp;
    //根节点,每个点删掉之后最多可以分为几块
    int root;
    inline int read()
    {
    	int x_=0,f_=1;
    	char c_=getchar();
    	while(c_<'0'||c_>'9')
    	{
    		if(c_=='-') f_=-1;
    		c_=getchar();
    	}
    	while(c_>='0'&&c_<='9')
    	{
    		x_=(x_<<1)+(x_<<3)+c_-'0';
    		c_=getchar();
    	}
    	return x_*f_;
    }
    struct node
    {
    	int id,w;
    } ans[N];
    void add(int a, int b)
    {
    	e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
    }
    
    void tarjan(int u)
    {
    	dfn[u] = low[u] = ++ timestamp;
    	//当前块儿内已经可以分出来的子树的个数
    	int cnt = 0;
    	for (int i = h[u]; ~i; i = ne[i])
    	{
    		int j = e[i];
    		if (!dfn[j])
    		{
    			tarjan(j);
    			low[u] = min(low[u], low[j]);
    			//说明j走不到u上面
    			if (low[j] >= dfn[u])
    			{
    				cnt ++;
    				if(u!=root || cnt>1)
    					++ans[u].w;
    			}
    		}
    		//如果已经搜过了
    		else
    			low[u] = min(low[u], dfn[j]);
    	}
    	//如果u不是根节点,而且cnt大于0
    	//还要加上父节点的那一部分
    	if (u != root && cnt)
    		cnt ++ ;
    	//取大
    }
    inline bool cmp_(node aa,node bb)
    {
    	if(aa.w==bb.w) return aa.id < bb.id;
    	return aa.w > bb.w;
    }
    int main()
    {
    	while(~scanf("%d%d", &n, &m))
    	{
    		if(!n && !m)
    			return 0;
    		//初始化,有判重数组的作用
    		memset(dfn, 0, sizeof dfn);
    		memset(h, -1, sizeof h);
    		for(int i=1; i<=n; i++) ans[i]= {i,0};
    		idx = timestamp = 0;
    		while (1)
    		{
    			int a=read(), b=read();
    			if(a==-1 && b==-1)
    				break;
    			a++,b++;
    			add(a, b), add(b, a);
    		}
    		for(int i=1; i<=n; i++)
    			ans[i].id=i;
    		root=1;
    		tarjan(1);
    		sort(ans+1,ans+1+n,cmp_);
    		for(int i=1; i<=m; ++i)
    			printf("%d %d
    ",ans[i].id-1,ans[i].w+1);
    		printf("
    ");
    	}
    	return 0;
    }
    
    
    
  • 相关阅读:
    JavaScript学习笔记(六)——Map、Set与iterable
    JavaScript学习笔记(五)——条件判断与循环
    JavaScript学习笔记(四)——对象
    JavaScript学习笔记(三)——数组
    抽象代数 第三章 群
    进栈序列为(1,2,3..,n)有多少种出栈顺序
    Win10 快捷键
    主项定理Master Method
    算法导论笔记 第三十章 多项式与快速傅里叶变化
    算法导论笔记 第二十九章 线性规划
  • 原文地址:https://www.cnblogs.com/QingyuYYYYY/p/12853732.html
Copyright © 2011-2022 走看看