P2451 [SDOI2005] 遗传代码

P2451 [SDOI2005] 遗传代码

题意简述

给出 \(m\) 个前后关系,让我们构造出一个最短的序列,使得其可以包含所有的前后关系(可重复出现同一数字)。

思路

如果把这输入看成一个图,那么题目的意思就是:要求我们遍历每一条边,每条边只访问一次,对于节点 \(i\),入边的数量 \(in_i\) 和出边 \(ou_i\),\(\max(in_i,ou_i)\) 意味着会经过点 \(i\) 的普通路径数量对于每一条路径点 \(i\) 会被作为端点描述一次,因此最终的描述点 \(i\) 出现的次数为 \(\max(in_i,ou_i)\) 因此答案就是 \(\sum^{i\le n}_{i=1} {\max(in_i,ou_i)}\)。随后我们发现可以过样例了仔细思考之下,发现若他不是个欧拉回路还要再多以一个起点来处理,也就是答案加一。最后时间复杂度是 \(O(n+m)\)。

实现

先将输入进来的有向边进行处理,统计存在的点和每个点的出度和入度。然后统计答案就是 \(ans+max(in[i],ou[i])\to ans\)。搜寻欧拉回路就用一个递归搜索这个以 \(i\) 起点连通分量里是否有 \(in_i \ne ou_i\),如果没有就可以使答案加一。

ACcode

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N=1001;
int m,ans,in[N],ou[N],fl;
bitset<N> f,vis;
vector<int> a,g[N];

void dfs(int u){
	vis[u]=1;
	if(in[u]^ou[u]) fl=0;//标记不是欧拉回路
	for(int i = 0;i<g[u].size();++i) if(!vis[g[u][i]]) dfs(g[u][i]);
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
//↑以上为初始化 ↑
//------------------------------
	cin >> m;
	for(int i = 1;i<=m;++i){
		int u,v;
		cin  >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
		if(!f[u]) a.push_back(u);
		if(!f[v]) a.push_back(v);
		ou[u]++,in[v]++,f[u]=f[v]=1;
	}
	for(int u:a){//只遍历存在的点
		ans+=max(in[u],ou[u]);//统计答案
		if(!vis[u])	fl=1,dfs(u),ans+=fl;
	}
	cout << ans << endl;
	return 0;
}
posted @ 2026-10-21 21:27  elon_giao  阅读(5)  评论(0)    收藏  举报