码迷,mamicode.com
首页 > 其他好文 > 详细

原始生物

时间:2019-10-27 22:24:12      阅读:80      评论:0      收藏:0      [点我收藏+]

标签:return   int   题目   out   void   因此   amp   表示   ace   

https://loj.ac/problem/10112

题目描述

  给出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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!