树专练

C电压
时间限制 : 10000 MS   空间限制 : - KB 
评测说明 : 1s,256m
问题描述
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搜一遍,然后找到一条被所有的奇数边包括并且不被所有的偶数边包括的边  并且找出这样的边的个数即可

#include<stdio.h> 
#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,ans,f,i,cnt=1;
int he[100010],de[100010],color[(100010)<<2],to[(100010)<<2],ne[(100010)<<2],a[100010],aa[100010];
void add(int x,int y)
{
cnt++;
to[cnt]=y;
ne[cnt]=he[x];
he[x]=cnt;
}//建树 
void dfs(int x)
{
	for(int i=he[x];i;i=ne[i])
	{
	if(de[to[i]]==-1)de[to[i]]=de[x]+1,color[i]=color[i^1]=1,dfs(to[i]);
}
}
void find(int x)
{
for(int i=he[x];i;i=ne[i])
{
if(color[i]&&de[to[i]]>de[x])find(to[i]),a[x]+=a[to[i]],aa[x]+=aa[to[i]];
}
if(de[x]&&a[x]==f&&!aa[x])ans++;//满足两个条件 
}
int main()
{
 scanf("%d%d",&n,&m);
//cin>>n>>m;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);//无向图 
}
memset(de,-1,sizeof(de));
for(int i=1;i<=n;i++)if(de[i]==-1)de[i]=0,dfs(i);//搜索

for(int j=1;j<=n;j++)
{
	
for(i=he[j];i;i=ne[i])
{
if(!color[i]&&de[to[i]]<de[j]){
if((de[j]-de[to[i]])&1)aa[j]++,aa[to[i]]--;
else f++,a[j]++,a[to[i]]--;
}
}

} 
if(f==1)ans++;
for(int i=1;i<=n;i++)if(!de[i])find(i);
//cout<<ans;
printf("%d",ans);
}

  

原文地址:https://www.cnblogs.com/cocacolalala/p/11377489.html