【刷题】BZOJ 2935 [Poi1999]原始生物

Description

原始生物的遗传密码是一个自然数的序列K=(a1,...,an)。原始生物的特征是指在遗传密码中连续出现的数对(l,r),即存在自然数i使得l=ai且r=ai+1。在原始生物的遗传密码中不存在(p,p)形式的特征。

求解任务:

请设计一个程序:

·读入一系列的特征。

·计算包含这些特征的最短的遗传密码。

·将结果输出

Input

第一行是一个整数n ,表示特征的总数。在接下来的n行里,每行都是一对由空格分隔的自然数l 和r ,1 <= l,r <= 1000。数对(l, r)是原始生物的特征之一。输入文件中的特征不会有重复。

Output

唯一一行应该包含一个整数,等于包含了PIE.IN中所有特征的遗传密码的最小长度。

Sample Input

12

2 3

3 9

9 6

8 5

5 7

7 6

4 5

5 1

1 4

4 2

2 8

8 6

Sample Output

15

注:

PIE.IN中的所有特征都包含在以下遗传密码中:

(8, 5, 1, 4, 2, 3, 9, 6, 4, 5, 7, 6, 2, 8, 6)

Solution

将限制建成边,于是题目的意思就变成了对于每一个联通块,找一个路径最短的欧拉回路/欧拉路径

欧拉路径还有最短的说法?!不可能的,所以肯定是定值。最短这个含义是体现在加边上的

考虑一个联通块,如果其本身是存在一个欧拉回路,即奇度数点为0,那么贡献就是边数加一

否则,奇度数点一定是大于0的偶数 (x),我们要加一些边使得图存在欧拉路径,还要让加的边最少,所以就是找 (x-2) 个点,两两连边,使图存在欧拉路径,这样的贡献就是加了边后的边数

最后依次考虑每个联通块就好了

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=1000+10;
int n,in[MAXN],out[MAXN],lt,ans,euler[MAXN],cnt,e,beg[MAXN],nex[MAXN*MAXN<<1],to[MAXN*MAXN<<1],vis[MAXN],app[MAXN];
template<typename T> inline void read(T &x)
{
	T data=0,w=1;
	char ch=0;
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
	x=data*w;
}
template<typename T> inline void write(T x,char ch='')
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
	if(ch!='')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void insert(int x,int y)
{
	to[++e]=y;
	nex[e]=beg[x];
	beg[x]=e;
}
inline void dfs(int x)
{
	vis[x]=1;
	chkmin(euler[cnt],in[x]==out[x]?1:0);
	for(register int i=beg[x];i;i=nex[i])
		if(!vis[to[i]])dfs(to[i]);
}
int main()
{
	read(n);
	for(register int i=1;i<=n;++i)
	{
		int u,v;read(u);read(v);app[u]=app[v]=1;
		in[v]++;out[u]++;
		insert(u,v);insert(v,u);
		chkmax(lt,u);chkmax(lt,v);
	}
	for(register int i=1;i<=lt;++i)
		if(!vis[i]&&app[i])euler[++cnt]=1,dfs(i);
	for(register int i=1;i<=lt;++i)
		if(app[i])ans+=max(in[i],out[i]);
	for(register int i=1;i<=cnt;++i)ans+=euler[i];
	write(ans,'
');
	return 0;
}
原文地址:https://www.cnblogs.com/hongyj/p/9457371.html