• 【bzoj4238】电压 DFS树


    题目描述

    你知道Just Odd Inventions社吗?这个公司的业务是“只不过是奇妙的发明(Just Odd Inventions)”。这里简称为JOI社。
    JOI社的某个实验室中有着复杂的电路。电路由n个节点和m根细长的电阻组成。节点被标号为1~N
    每个节点有一个可设定的状态【高电压】或者【低电压】。每个电阻连接两个节点,只有一端是高电压,另一端是低电压的电阻才会有电流流过。两端都是高电压或者低电压的电阻不会有电流流过。
    某天,JOI社为了维护电路,选择了一根电阻,为了能让【只有这根电阻上的电流停止流动,其他M-1根电阻中都有电流流过】,需要调节各节点的电压。为了满足这个条件,能选择的电阻共有多少根?
    对了,JOI社这个奇妙的电路是用在什么样的发明上的呢?这是公司内的最高机密,除了社长以外谁都不知道哦~
    现在给出电路的信息,请你输出电路维护时可以选择使其不流的电阻的个数。

    输入

    第一行两个空格分隔的正整数N和M,表示电路中有N个节点和M根电阻。
    接下来M行,第i行有两个空格分隔的正整数Ai和Bi(1<=Ai<=N,1<=Bi<=N,Ai≠Bi),表示第i个电阻连接节点Ai和节点Bi。

    输出

    输出一行一个整数,代表电路维护时可选择的使其不流的电阻个数。

    样例输入

    4 4
    1 2
    2 3
    3 2
    4 3

    样例输出

    2


    题解

    DFS树

    简单分析一下题目可知题目要求多少条边在简单奇环上的边的交集上,且不再简单偶环上。

    判断简单环的最好方法是DFS树,所以我们可以先把整张无向图DFS一遍,然后分为树边和返祖边讨论。

    对于一条返祖边,如果它连接的两个点的深度差为偶数,说明它在奇环上;否则在偶环上。并且它覆盖的边所在的奇环数或偶环数+1.

    我们可以差分一下,在两个点上边打上标记,然后再遍历一遍求出每条树边在多少个奇环上,在多少个偶环上。如果满足条件则将答案+1.

    注意:如果只有一条返祖边在奇环上,则将答案+1,否则对答案都没有贡献。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 100010
    using namespace std;
    int head[N] , to[N << 2] , flag[N << 2] , next[N << 2] , s1[N] , s2[N] , t1[N] , t2[N] , cnt = 1 , deep[N] , num , ans;
    void add(int x , int y)
    {
    	to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
    }
    void dfs(int x)
    {
    	int i;
    	for(i = head[x] ; i ; i = next[i])
    		if(deep[to[i]] == -1)
    			deep[to[i]] = deep[x] + 1 , flag[i] = flag[i ^ 1] = 1 , dfs(to[i]);
    }
    void query(int x)
    {
    	int i;
    	for(i = head[x] ; i ; i = next[i])
    		if(flag[i] && deep[to[i]] > deep[x])
    			query(to[i]) , s1[x] += s1[to[i]] , s2[x] += s2[to[i]];
    	if(deep[x] && s1[x] == num && !s2[x]) ans ++ ;
    }
    int main()
    {
    	int n , m , i , x , y;
    	scanf("%d%d" , &n , &m);
    	for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x);
    	memset(deep , -1 , sizeof(deep));
    	for(i = 1 ; i <= n ; i ++ )
    		if(deep[i] == -1)
    			deep[i] = 0 , dfs(i);
    	for(x = 1 ; x <= n ; x ++ )
    	{
    		for(i = head[x] ; i ; i = next[i])
    		{
    			if(!flag[i] && deep[to[i]] < deep[x])
    			{
    				if((deep[x] - deep[to[i]]) & 1) s2[x] ++ , s2[to[i]] -- ;
    				else num ++ , s1[x] ++ , s1[to[i]] -- ;
    			}
    		}
    	}
    	if(num == 1) ans ++ ;
    	for(i = 1 ; i <= n ; i ++ )
    		if(!deep[i])
    			query(i);
    	printf("%d
    " , ans);
    	return 0;
    }
    

     

  • 相关阅读:
    mysql修改密码策略
    YUM方法安装mysql5.7版本
    redis-5.0.5安装(linux centos)
    centos7 安装php7扩展
    Linux df
    Spotlight监控工具使用
    Linux 安装iostat命令
    转载:数据库连接池到底应该设置多大?
    cqlsh 一个错误
    Linux Top命令详解
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7123480.html
Copyright © 2020-2023  润新知