zoukankan      html  css  js  c++  java
  • 题解 CF51F 【Caterpillar】

    根据毛毛虫的定义,我们不难发现在双连通分量中的点我们都需要进行合并操作,所以我们先进行(tarjan)缩边双连通分量,使原图变成一棵树,缩点对答案产生的贡献为每个双连通分量的(size-1)

    然后我们继续考虑树的情况,发现,若要将树变成毛毛虫,最优的操作是保留叶子节点和除去叶子后的直径,于是我们记录叶子节点个数(le),除去叶子后的直径长度(dist)

    但可能不止不止一棵树,缩点后可能为森林,所以最后还需将森林合并,我们再记录树的个数(num)

    则最终答案为(ans= displaystylesum_{i=1}^{co\_cnt}(siz[i]-1)+co\_cnt-dist-le+num-1)

    其他实现的细节就看代码吧

    (code:)

    #include<bits/stdc++.h>
    #define maxn 20010
    #define maxm 200010
    using namespace std;
    template<typename T> inline void read(T &x)
    {
    	x=0;char c=getchar();bool flag=false;
    	while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	if(flag)x=-x;
    }
    int n,m,ans,num;
    struct Edge
    {
    	int x,y;
    }ed[maxm];
    struct edge
    {
    	int to,nxt;
    }e[maxm];
    int head[maxn],edge_cnt=1;
    void add(int from,int to)
    {
    	e[++edge_cnt]=(edge){to,head[from]};
    	head[from]=edge_cnt;
    }
    int dfn[maxn],low[maxn],dfn_cnt;
    bool bri[maxn];
    void tarjan(int x,int ed)
    {
    	dfn[x]=low[x]=++dfn_cnt;
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int y=e[i].to;
    		if(!dfn[y])
    		{
    			tarjan(y,i);
    			low[x]=min(low[x],low[y]);
    			if(dfn[x]<low[y]) bri[i]=bri[i^1]=true;
    		}
    		else if(i!=(ed^1)) low[x]=min(low[x],dfn[y]);
    	}
    }
    int co_cnt;
    int co[maxn],siz[maxn];
    void dfs_co(int x)
    {
    	co[x]=co_cnt;
    	siz[co_cnt]++;
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int y=e[i].to;
    		if(co[y]||bri[i]) continue;
    		dfs_co(y);
    	}
    }
    void clear()
    {
    	edge_cnt=1;
    	memset(head,0,sizeof(head));
    }
    int le;
    bool vis[maxn],leaf[maxn];
    void dfs_le(int x)
    {
    	vis[x]=true;
    	bool son=true;
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int y=e[i].to;
    		if(vis[y]) continue;
    		son=false;
    		dfs_le(y);
    	}
    	if(son)
    	{
    		leaf[x]=true;
    		le++;
    	}
    }
    int nd,maxd,dist;
    int dis[maxn];
    void dfs_find(int x,int fa,int de)
    { 
        vis[x]=true; 
        if(de>=maxd)
        {
            maxd=de;
            nd=x;
    	}
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to,v=1;
            if(y==fa||leaf[y]) continue;
            dfs_find(y,x,de+v);
        }
    }	
    int main()
    {
    	read(n),read(m);
    	for(int i=1;i<=m;++i)
    	{
    		int a,b;
    		read(a),read(b);
    		add(a,b),add(b,a);
    		ed[i]=(Edge){a,b};
    	}
    	for(int i=1;i<=n;++i)
    		if(!dfn[i])
    			tarjan(i,0);
    	for(int i=1;i<=n;++i)
    	{
    		if(!co[i])
    		{
    			co_cnt++;
    			dfs_co(i);
    		}
    	}
    	for(int i=1;i<=co_cnt;++i)
    		ans+=siz[i]-1;
    	clear();
    	for(int i=1;i<=m;++i)
    	{
    		int x=ed[i].x,y=ed[i].y;
    		if(co[x]==co[y]) continue;
    		add(co[x],co[y]),add(co[y],co[x]);
    	}
    	for(int i=1;i<=co_cnt;++i)
    	{
    		if(!vis[i])
    		{
    			dfs_le(i);
    			num++;
    			int tot=0;
    			for(int p=head[i];p;p=e[p].nxt) tot++;
    			if(tot==1)
    			{
    				leaf[i]=true;
    				le++;
    			}
    		}
    	}
    	memset(vis,0,sizeof(vis));
    	for(int i=1;i<=co_cnt;++i)
    	{
    		if(!vis[i]&&!leaf[i])
    		{
    			nd=maxd=0;
    			dfs_find(i,0,1);
    			dfs_find(nd,0,1);
    			dist+=maxd;
    		}
    	}
    	printf("%d",ans+co_cnt-dist-le+num-1);
    	return 0;
    }
    
  • 相关阅读:
    CF149D Coloring Brackets
    CF508D
    CF483C Diverse Permutation
    【纪念】我写过几乎最长的代码
    .net core图片上传详解
    layui插件croppers的使用
    关于日常操作中sql的性能
    leeCode 278
    leeCode刷题 1078
    leeCode刷题 lc184
  • 原文地址:https://www.cnblogs.com/lhm-/p/12229817.html
Copyright © 2011-2022 走看看