• 【BZOJ4238】电压 DFS树


    【BZOJ4238】电压

    Description

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

    Input

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

    Output

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

    Sample Input

    4 4
    1 2
    2 3
    3 2
    4 3

    Sample Output

    2

    HINT

    可以选择第一根电阻或第四根电阻。

     

    2<=N<=10^5
    1<=M<=2*10^5
    不保证图是连通的,不保证没有重边

    题解:题意差不多就是给你一个无向图,让你找出一条边,将它的两个顶点染成相同的颜色,使得剩下的图是一个二分图。

    判断二分图就是找奇环,自然要用到DFS树,我们找出这条边后,一定要保证剩下的图中不含奇环。所以,如果一条边被所有奇环包含,我们可以选择它。

    但是好像不对?如果一条边既被奇环包含又被偶环包含,那么去掉这条边后,奇半环和偶半环又组合成了一个奇环,所以我们选择的边在满足被所有奇环包含的同时,还要满足不能被偶环包含。

    具体方法:用DFS树处理出每条边被多少个奇环和偶环包含就行了。

    你可能会疑问:

    1.假如原图中没有奇环怎么办?那么任意一条不被偶环覆盖的边都是可行的,你会发现这种情况上面已经处理过了。
    2.如果有多个互不相交的奇环怎么办?答案显然是0啊。。。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int maxn=100010;
    int n,m,cnt,H1,H2,ans;
    int to[maxn<<2],next[maxn<<2],vis[maxn<<2],val[maxn<<1],head[maxn],dep[maxn],h1[maxn],h2[maxn];
    inline int z(int x){	return x>0?x:-x;}
    int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    void add(int a,int b)
    {
    	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
    }
    void dfs(int x)
    {
    	for(int i=head[x];i!=-1;i=next[i])
    	{
    		if(vis[i])	continue;
    		vis[i^1]=1;
    		if(!dep[to[i]])	dep[to[i]]=dep[x]+1,dfs(to[i]),h1[x]+=h1[to[i]],h2[x]+=h2[to[i]];
    		else	if((dep[x]-dep[to[i]])&1)	H2++,h2[x]++,h2[to[i]]--;
    		else	H1++,h1[x]++,h1[to[i]]--;
    	}
    }
    int main()
    {
    	n=rd(),m=rd();
    	int i,a,b;
    	memset(head,-1,sizeof(head));
    	for(i=1;i<=m;i++)	a=rd(),b=rd(),add(a,b),add(b,a);
    	for(i=1;i<=n;i++)	if(!dep[i])	dep[i]=1,dfs(i);
    	for(i=0;i<cnt;i+=2)
    	{
    		a=to[i],b=to[i^1];
    		if(dep[a]<dep[b])	swap(a,b);
    		if(dep[a]==dep[b]+1)
    		{
    			if(h1[a]==H1&&!h2[a])	ans++;
    		}
    		else	if(!((dep[a]-dep[b])&1)&&H1==1)	ans++;
    	}
    	printf("%d",ans);
    	return 0;
    }
  • 相关阅读:
    JavaScript的作用域和块级作用域概念理解
    正则表达式中组的理解
    正则表达式的字符组取反(负值字符集合/范围)^必须出现在起始位置
    利用TortoiseGit(小乌龟)将项目上传至GitHub网站
    (.Net) NLog 记录日志功能
    关于网站中引用COM组件的部署问题
    备份与还原ORACLE数据库(通过CMD命令执行)
    C# Task中的Func, Action, Async与Await的使用
    ASP.NET WebAPI 项目示例(增删改查)
    .NET内存泄漏(之 静态事件)
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7123553.html
Copyright © 2020-2023  润新知