SP211 PRIMIT - Primitivus recurencis

SP211 PRIMIT - Primitivus recurencis

题意简述

\(t\) 组数据,给出 \(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(t(n+m))\)。

实现

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

ACcode

#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2,3,"Ofast","inline")
#define int long long
#define endl '\n'
const int N=1001;
int T,n,m,ans,in[N],ou[N],fl;
bitset<N> a,vis;
vector<int> 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 >> T;
	while(T--){
		a.reset(),vis.reset(),memset(in,0,sizeof(in)),memset(ou,0,sizeof(ou)),n=ans=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);
			ou[u]++,in[v]++,a[u]=a[v]=1;
			n=max({n,u,v});
		}
		for(int i = 0;i<=n;++i){
			if(!a[i]) continue;
			ans+=max(in[i],ou[i]);
			if(!vis[i])	fl=1,dfs(i),ans+=fl;
		}
		cout << ans << endl;
		for(int i = 1;i<=n;++i) g[i].clear();
	}
	return 0;
}
posted @ 2026-10-21 21:26  elon_giao  阅读(4)  评论(0)    收藏  举报