【Codeforces Beta Round #48】 Codeforces 51F Caterpillar

177 篇文章 0 订阅
87 篇文章 1 订阅

An undirected graph is called a caterpillar if it is a connected graph
without cycles and it has such a path p that any vertex is located at
a distance of at most 1 from the path p. The caterpillar can contain
loops (edges from a vertex to itself) but cannot contain multiple
(parallel) edges.

The picture contains an example of a caterpillar:

You are given an undirected graph G. You are allowed to do a merging
operations, each such operation merges two vertices into one vertex.
For that two any vertices a and b (a�6�5≠�6�5b) are chosen. These
verteces are deleted together with their edges (which are incident to
at least one of the vertices a or b) but a new vertex w is added
together with edges (x,�6�5w) for each edge (a,�6�5w) and/or
(b,�6�5w). If there was the edge (a,�6�5b) it transforms to the loop
(w,�6�5w). The resulting graph (after the merging operation) may
contain multiple (parallel) edges between pairs of vertices and loops.
Let us note that this operation decreases the number of vertices of
graph by 1 but leaves the number of edges in the graph unchanged.

The merging operation can be informally described as a unity of two
vertices of the graph into one with the natural transformation of the
graph edges.

You may apply this operation consecutively and make the given graph to
be a caterpillar. Write a program that will print the minimal number
of merging operations required to make the given graph a caterpillar.

Input The first line contains a pair of integers n, m
(1�6�5≤�6�5n�6�5≤�6�52000;0�6�5≤�6�5m�6�5≤�6�5105), where n represents
the number of vertices in the graph and m is the number of edges in
it. Then the following m lines contain edge descriptions, one edge
description per line. Every line contains a pair of integers ai,�6�5bi
(1�6�5≤�6�5ai,�6�5bi�6�5≤�6�5n;ai�6�5≠�6�5bi), ai,�6�5bi which
represent the indices of the vertices connected by the edge. The
vertices are numbered from 1 to n. In the given graph it will be no
more than one edge between any pair of vertices. The given graph is
not necessarily connected.

Output Print the minimal required number of operations.

首先注意到,环一定不会存在,所以可以先缩点成森林。对于每棵树,找到留下的链,那么除了叶子节点之外的所有点都要消掉,所以应该取最长链,这样对于一块大小为n的联通块,花费为n-叶子数-最长链点数+2【因为链上两个端点的点被算了两次】。最后连通起来,只需要把每一块的链首尾相连,所以花费为联通块个数-1。注意联通块个数和联通块数量是可以一起算的,最后特判一下孤立点的情况。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int f1[2010],n1[200010],t1[200010],
bel[200010],dfn[200010],low[200010],sta[2010],
m,n,num,clo,top;
bool have[2010][2010],vis[2010];
vector<int> to[2010];
void add(int num,int u,int v)
{
    n1[num]=f1[u];
    f1[u]=num;
    t1[num]=v;
}
void dfs1(int u,int fa)
{
    int i,v,x;
    dfn[u]=low[u]=++clo;
    sta[++top]=u;
    for (i=f1[u];i;i=n1[i])
      if ((v=t1[i])!=fa)
      {
        if (!dfn[v])
        {
            dfs1(v,u);
            low[u]=min(low[u],low[v]);
        }
        else low[u]=min(low[u],dfn[v]);
      }
    if (low[u]==dfn[u])
    {
        num++;
        do
        {
            x=sta[top--];
            bel[x]=num;
        }
        while (x!=u);
    }
}
int dfs2(int u,int dis,int fa,int &p)
{
    vis[u]=1;
    int i,v,ret,tem1,tem2;
    p=u;
    ret=dis;
    for (i=0;i<to[u].size();i++)
      if ((v=to[u][i])!=fa)
      {
        tem1=dfs2(v,dis+1,u,tem2);
        if (tem1>ret)
        {
            ret=tem1;
            p=tem2;
        }
      }
    return ret;
}
int main()
{
    int i,j,u,v,x,y,ans,tem;
    scanf("%d%d",&n,&m);
    for (i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        add(i*2,x,y);
        add(i*2+1,y,x);
    }
    for (i=1;i<=n;i++)
      if (!dfn[i])
        dfs1(i,-1);
    for (i=1;i<=n;i++)
      for (j=f1[i];j;j=n1[j])
        if (!have[u=bel[i]][v=bel[t1[j]]]&&u!=v)
        {
            have[u][v]=1;
            to[u].push_back(v);
        }
    ans=n-1;
    for (i=1;i<=num;i++)
      if (!vis[i])
      {
        dfs2(i,1,-1,u);
        tem=dfs2(u,1,-1,v);
        if (tem!=1)
          ans-=tem-3;
      }
    for (i=1;i<=num;i++)
      if (to[i].size()==1)
        ans--;
    printf("%d\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值