【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;
}
时间: 2024-10-20 05:05:58

【BZOJ4238】电压 DFS树的相关文章

BZOJ4238电压

Description 你知道Just Odd Inventions社吗?这个公司的业务是"只不过是奇妙的发明(Just Odd Inventions)".这里简称为JOI社. JOI社的某个实验室中有着复杂的电路.电路由n个节点和m根细长的电阻组成.节点被标号为1~N 每个节点有一个可设定的状态[高电压]或者[低电压].每个电阻连接两个节点,只有一端是高电压,另一端是低电压的电阻才会有电流流过.两端都是高电压或者低电压的电阻不会有电流流过. 某天,JOI社为了维护电路,选择了一根电阻

BZOJ 4541: [Hnoi2016]矿区 平面图转对偶图+DFS树

4541: [Hnoi2016]矿区 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 433  Solved: 182[Submit][Status][Discuss] Description 平面上的矿区划分成了若干个开发区域.简单地说,你可以将矿区看成一张连通的平面图,平面图划分为了若 干平面块,每个平面块即为一个开发区域,平面块之间的边界必定由若干整点(坐标值为整数的点)和连接这些整点 的线段组成.每个开发区域的矿量与该开发区域的面积有关:具

【bzoj4016】[FJOI2014]最短路径树问题 堆优化Dijkstra+DFS树+树的点分治

题目描述 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径A为1,32,11,路径B为1,3,2,11,路径B字典序较小.注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小).到达该点后按原路返回,然后往其他点走,直到所有点都走过. 可以知道,经过的边会构成一棵最短路径树.请问,在这棵最短路径树上,最长的包含K个点的简单路径长度为多长

bzoj-4238 电压

题意: 给出一个n个结点m条边的无向图,用两种颜色来对结点染色: 求图中有多少条边,可以存在一种方案,使这条边两段的颜色相同而其他边两端颜色不同: n<=100000,m<=200000: 题解: 这题感觉正解大框很容易想,但是最终写出来还是很难的似乎: 最简单的暴力就是枚举边然后给图染色: 然后还有n==m的基环树,搜个环讨论一下就又有一些分: 正解的话显然要找环,然而如何找环Tarjan早已给出了答案: 先搜一个DFS树,这样图中所有的边就分为了树边和非树边: 又因为DFS树的性质,这里的

zstu.4191: 无向图找环(dfs树 + 邻接表)

4191: 无向图找环 Time Limit: 5 Sec  Memory Limit: 128 MB Submit: 117  Solved: 34 Description 给你一副无向图,每条边有边权,保证图联通,现在让你判断这个图是否有异或值大于零的环存在. Input 多组测试数据,每组先输入两个数n m,表示图的点跟边的数量. 然后是m行,每行三个数a b c.代表一条边的起点,终点,边权. 1 <= n<= 100000, 1 <= m <= 200000. 1 <

【BZOJ4424】Cf19E Fairy DFS树

[BZOJ4424]Cf19E Fairy Description 给定 n 个点,m 条边的无向图,可以从图中删除一条边,问删除哪些边可以使图变成一个二分图. Input 第 1 行包含两个整数 n,m.分别表示点数和边数.第 2 到 m+1 行每行两个数 x,y 表示有一条(x,y)的边. Output 输出第一行一个整数,表示能删除的边的个数.接下来一行按照从小到大的顺序输出边的序号. Sample Input 4 4 1 2 1 3 2 4 3 4 Sample Output 4 1 2

HDOJ 4582 - DFS spanning tree - DFS树,贪心

题目大意: 给定一个N个点.M条边的无向图Graph,以及从点1开始进行DFS形成的树Tree,定义"T-Simple Circle"为Graph中的环,要求其中只含一条不属于Tree的边. 将Graph中的一些边进行染色,使得其中每个T-simple Circle都至少包含一条被染色的边,求最少需要染色的边数. N≤2e3,M≤2e4 本题关键的一点在于Tree是一棵DFS生成树,这样Tree以外的边只可能将某个点与它在Tree中的祖先相连(用反证法可以证明,只有这样才能维持DFS树

BZOJ5203 [NEERC2017 Northern] Grand Test 【dfs树】【构造】

题目分析: 首先观察可知这是一个无向图,那么我们构建出它的dfs树.由于无向图的性质我们可以知道它的dfs树只有返祖边.考虑下面这样一个结论. 结论:若一个点的子树中(包含自己)有两个点有到它祖先的返祖边(不包括到它自己), 首先我们证明S和T肯定在DFS树中是祖先关系,接着证明到T至少有一条返祖边,那么这个结论就是显然的了. 代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 102000; 5

DFS 树

声明 本文部分内容来自 Codeforces 上的一篇博客,侵删. DFS 是一种常见的图遍历方法. 考虑 无向图 的遍历过程:我们访问一个节点,遍历它的所有相邻节点,如果没有访问则去访问.不难发现每个节点只会被访问一次,也即这些节点和所有访问到的边可以构成一棵树,我们称这棵树为 DFS 树.访问过的边称为生成边(span edge),没有访问的称为后向边(back edge). 仔细观察后向边,我们可以发现一些性质: 每条后向边只会连接祖先和子孙,不会有兄弟相连. 这个很好证明,如果有一条边连