标签:return int 题目 out void 因此 amp 表示 ace
题目描述
给出n个约束条件(l,r),在S这个序列中存在连续的两个数是l、r,求满足这些条件的序列的最短长度。
思路
我们考虑以(l,r)作为一条单向边,表示l后需要加r,因此对于整个图来说,如果它是连通的,那么就是欧拉回路的长度。但图如果不连通,我么就要考虑加最少的边使得图连通并且存在欧拉回路。有向图存在欧拉回路的条件是每个节点的入度等于出度,我们考虑对于单个连通块内,如果要使得这个连通分量内存在欧拉回路,至少要连从u连出in[u]-out[u]条边(统计一个的差即可,因为总入度等于总出度),所以累加起来即为满足这个连通分量需要加的边数,我们计为a[i]。
那么对于每个非孤立点的连通分量,统计答案时,如果a[i]≠0,那么就需要额外连a[i]条边,这个数目可以包括连通块合并;而a[i]=0,就需要在连出一条边使得连通块之间连通(相应的,为了维护其仍是欧拉图,目标的连通分量也会连出一条边,但这不影响答案的统计,因为目标的分量相当于少连一条入边,多练一条出边)。最后再加上必须的n条边就是答案。
代码
#include <bits/stdc++.h> using namespace std; const int N=1100; int fa[N]; int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } void f_union(int x,int y) { int fx=find(x),fy=find(y); if(fx!=fy)fa[fx]=fy; } int read() { int res=0,w=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)w=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){res=(res<<3)+(res<<1)+ch-‘0‘;ch=getchar();} return res*w; } int in[N],out[N],a[N]; bool used[N]; int main() { int n,m=0; n=read(); for(int i=1;i<=1000;i++) fa[i]=i; for(int i=1;i<=n;i++) { int x=read(),y=read(); out[x]++;in[y]++; m=max(m,max(x,y)); f_union(x,y); } for(int i=1;i<=m;i++) { int x=find(i); if(i==find(i)&&in[i]+out[i]>0)used[i]=1;//非孤立点记录且是连通分量的父节点 if(in[i]>out[i]) a[x]+=in[i]-out[i]; } int ans=0; for(int i=1;i<=m;i++) if(used[i]) //这个点代表着一个连通分量 { if(a[i]!=0) ans+=a[i]; else ++ans; } printf("%d",ans+n); return 0; }
标签:return int 题目 out void 因此 amp 表示 ace
原文地址:https://www.cnblogs.com/fangbozhen/p/11749277.html