【总结】欧拉回路

A.原始生物

一句话题意:给定一个连通块,求其经过所有边的节点数量最少和(不一定是一笔画,可以多笔划)。

于是我们可以统计每个点在路径中出现的次数,累加即可

可以这样想:对于节点i的入度为 i n in in,出度为 o u t out out,则出现次数为 m a x ( i n , o u t ) max(in,out) max(in,out).因为数量少的一类边一定先被遍历完,所以最后还要单独构造 a b s ( i n − o u t ) abs(in-out) abs(inout)个点。

题目并没有告诉你整个图联通,我们可以推广,分别求出每个连通块的答案,累加即可。

然而,这道题的坑点是要判断连通块是否存在欧拉回路。如果是,则答案必须加一。因为起点最后又被加入了,比实际 i n [ i ] in[i] in[i]大1.

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;

void read(int &x) {
    
    
	int f=1;x=0;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^48);c=getchar();}
	x*=f;
}


int n=1000,in[N],out[N],fa[N],sum[N],flag[N],ans;
int m;
bool pos[N];

int find(int x) {
    
    
	if(fa[x]!=x) fa[x]=find(fa[x]);
	return fa[x];
}



int main() {
    
    
	for(int i=1;i<=1000;i++) fa[i]=i,s[i]=1;
	read(m);
	for(int i=1,x,y;i<=m;i++) {
    
    
		read(x),read(y);
		pos[x]=pos[y]=1;
		out[x]++,in[y]++;
		int u=find(x),v=find(y);
		if(u!=v) {
    
    
			fa[u]=v;
		}
	}
	for(int i=1;i<=n;i++) {
    
    
		if(pos[i]) {
    
    
			sum[find(i)]+=max(in[i],out[i]);
			if(in[i]!=out[i]) flag[find(i)]=1;
		}
	}
	for(int i=1;i<=n;i++) {
    
    
		if(pos[i]&&fa[i]==i) {
    
    
			ans+=sum[i];
			if(!flag[i]) ans++;
		}
	}
	printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/cqbzlydd/article/details/108135958
今日推荐