题解 CF51F 【Caterpillar】
根据毛毛虫的定义,我们不难发现在双连通分量中的点我们都需要进行合并操作,所以我们先进行\(tarjan\)缩边双连通分量,使原图变成一棵树,缩点对答案产生的贡献为每个双连通分量的\(size-1\)
然后我们继续考虑树的情况,发现,若要将树变成毛毛虫,最优的操作是保留叶子节点和除去叶子后的直径,于是我们记录叶子节点个数\(le\),除去叶子后的直径长度\(dist\)
但可能不止不止一棵树,缩点后可能为森林,所以最后还需将森林合并,我们再记录树的个数\(num\)
则最终答案为\(ans= \displaystyle\sum_{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;
}
题解 CF51F 【Caterpillar】的更多相关文章
- CF51F Caterpillar (边双+树形DP)
题目传送门 题目大意:给你一张n个点m条边的图.每次操作可以把两个点合并成一个(与之相连的边也都要连到新点上).求把图中每个联通块都变成“毛毛虫”的最小操作次数.“毛毛虫”必须是一棵树(可以存在自环) ...
- Educational Codeforces Round 10 A. Gabriel and Caterpillar 模拟
A. Gabriel and Caterpillar 题目连接: http://www.codeforces.com/contest/652/problem/A Description The 9-t ...
- 2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...
- noip2016十连测题解
以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...
- BZOJ-2561-最小生成树 题解(最小割)
2561: 最小生成树(题解) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1628 Solved: 786 传送门:http://www.lyd ...
- Codeforces Round #353 (Div. 2) ABCDE 题解 python
Problems # Name A Infinite Sequence standard input/output 1 s, 256 MB x3509 B Restoring P ...
- 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解
题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...
- 2016ACM青岛区域赛题解
A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- poj1399 hoj1037 Direct Visibility 题解 (宽搜)
http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...
随机推荐
- 《Java核心技术》笔记:第7章 异常、断言和日志
1. 异常 (P 280)异常处理需要考虑的问题: 用户输入错误 设备错误 物理限制 代码错误 (P 280)传统的处理错误的方法是:返回一个特殊的错误码,常见的是返回-1或者null引用 (P 28 ...
- 28_链表插入和删除算法的演示.swf
#include<stdio.h> #include<malloc.h> #include <stdio.h> #include <stdlib.h> ...
- java 虚拟机指令重新排序
指令重排序是JVM为了优化指令,提高程序运行效率,在不影响单线程程序执行结果的前提下,尽可能地提高并行度.编译器.处理器也遵循这样一个目标.注意是单线程.多线程的情况下指令重排序就会给程序员带来问题. ...
- 利用xampp集成环境搭建pikachu靶场及部分问题解决
xampp的环境部署 1.本地服务器的搭建 首先要到官网下载xampp https://www.apachefriends.org/zh_cn/index.html 有各个不同的系统版本,这里我们选择 ...
- c++数字转化为字符串、字符串转换为数字
char ch[20]; int i =1; int j = 2; char *p = "34567"; 数字装换为字符串 sprintf(ch , "%d,%d&quo ...
- Redis系列(六):数据结构QuickList(快速列表)源码解析
1.介绍 Redis在3.2版本之前List的底层编码是ZipList和LinkedList实现的 在3.2版本之后,重新引入了QuickList的数据结构,列表的底层都是QuickList实现 当L ...
- C++ 自动资源释放的单例模式
代码思想就是程序结束时会自动释放静态/全局资源时删除单例资源. //.h class CSingleton { public: static CSingleton* Singleton() { ret ...
- Python3笔记008 - 2.5 运算符
第2章 python语言基础 运算符:是一些特殊的符号,主要用于数学计算等. 表达式:使用运算符将不同类型的数据按照一定的规则连接起来的式子. 分类:算术运算符.赋值运算符.比较运算符.逻辑运算符.位 ...
- 设置overflow:hiden行内元素会发生偏移的现象
父级元素包含几个行内元素 <div id="box"> <p> <span>按钮</span> <span>测试文字文字 ...
- P3574 FAR-FarmCraft 题解
题目 In a village called Byteville, there are \(n\) houses connected with \(n-1\) roads. For each pair ...