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;
}

浙公网安备 33010602011771号