CF51F Caterpillar (边双+树形DP)
题目大意:给你一张n个点m条边的图。每次操作可以把两个点合并成一个(与之相连的边也都要连到新点上)。求把图中每个联通块都变成“毛毛虫”的最小操作次数。“毛毛虫”必须是一棵树(可以存在自环),且其中必须存在一条主链,使得主链外的点到主链上的任意一点距离为1。$n\leq 2000,m\leq 10^{5}$
树上乱搞题目×1
首先把原图用边双$tarjan$缩成一棵树
然后我们想办法找出这条主链,似乎也只能$DP$了
定义$f(x,0/1)$表示 主链一端在$x$子树内另一端在$x$点/主链两个端点都在$x$子树内 付出的最小代价
对于不在主链上的点,需要把整颗子树合并成一个点,画一画图发现这个数量就是这个子树内的叶节点数量!
$f(x,0)=min{f(v,0)+合并其他子树的花费}$
$f(x,1)=min(f(v_{0},0)+f(v_{1},0)+合并其他子树的花费)$
合并其他子树的花费很好推,但式子太长就不放了
这也意味着我们$DP$时需要挑一个非叶节点为根进行$DP$
题目并没有保证所有点都在一个联通块内..每个联通块都要统计一遍,好麻烦..
时间可以被菊花图卡成$O(n^{2})$,但仍能轻松通过全部数据
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 2010
#define M1 100050
using namespace std;
const int inf=0x3f3f3f3f; template <typename _T> void read(_T &ret)
{
ret=; _T fh=; char c=getchar();
while(c<''||c>''){ if(c=='-') fh=-; c=getchar(); }
while(c>=''&&c<=''){ ret=ret*+c-''; c=getchar(); }
ret=ret*fh;
} struct Edge{
int to[M1*],nxt[M1*],val[M1*],head[N1],cte;
void ae(int u,int v,int w)
{ cte++; to[cte]=v; nxt[cte]=head[u]; val[cte]=w; head[u]=cte; }
}e,g; int n,m,num;
int dfn[N1],low[N1],use[N1],stk[N1],dad[N1],tp,tim,que[N1],tl;
int f[N1][],sum[N1],sz[N1],inc[N1],vis[N1];
void init()
{
memset(f,,(num+)*); memset(sz,,(num+)*); memset(sum,,(num+)*);
memset(vis,,(num+)*); memset(inc,,(num+)*); memset(g.head,,(num+)*);
tl=tp=tim=num=; g.cte=;
} void tarjan(int x,int fa)
{
int j,v; que[++tl]=x;
dfn[x]=low[x]=++tim; use[x]=; stk[++tp]=x;
for(j=e.head[x];j;j=e.nxt[j])
{
if(e.val[j]==fa) continue;
v=e.to[j];
if(!dfn[v]){
tarjan(v,e.val[j]);
low[x]=min(low[x],low[v]);
}else if(use[v]){
low[x]=min(low[x],dfn[v]);
}
}
if(low[x]==dfn[x])
{
num++;
while(stk[tp]!=x)
use[stk[tp]]=, dad[stk[tp]]=num, tp--;
use[stk[tp]]=, dad[stk[tp]]=num, tp--;
}
} void dfs(int x,int fa)
{
int j,v; sz[x]=; vis[x]=;
for(j=g.head[x];j;j=g.nxt[j])
{
v=g.to[j]; if(v==fa) continue;
dfs(v,x);
sz[x]+=sz[v]; sum[x]+=sum[v];
}
int k,v0,v1;
if(inc[x]>) f[x][]=f[x][]=inf; else sum[x]=;
for(j=g.head[x];j;j=g.nxt[j])
{
v0=g.to[j]; if(v0==fa) continue;
f[x][]=min(f[x][],f[v0][]+(sz[x]--sz[v0])-(sum[x]-sum[v0]));
for(k=g.nxt[j];k;k=g.nxt[k])
{
v1=g.to[k]; if(v1==fa) continue;
f[x][]=min(f[x][],f[v0][]+f[v1][]+(sz[x]-sz[v0]-sz[v1]-)-(sum[x]-sum[v0]-sum[v1]));
}
}
}
int de; int solve(int x)
{
int i,j,ans=,root; init();
tarjan(x,);
if(num<=){ return tl-num; }
for(i=;i<=tl;i++)
{
x=que[i];
for(j=e.head[x];j;j=e.nxt[j]) if(dad[x]!=dad[e.to[j]])
g.ae(dad[x],dad[e.to[j]],), inc[dad[e.to[j]]]++;
}
for(i=;i<=num;i++) if(inc[i]>){ root=i; dfs(root,); break; }
for(i=,ans=inf;i<=num;i++) if(inc[i]>)
if(i!=root) ans=min(ans,f[i][]+(num-sz[i])-(sum[root]-sum[i]));
else ans=min(ans,f[i][]);
return ans+tl-num;
} int main()
{
int i,j,x,y,ans=-;
scanf("%d%d",&n,&m);
for(i=;i<=m;i++) read(x), read(y), e.ae(x,y,i), e.ae(y,x,i);
for(i=;i<=n;i++) if(!dfn[i]) ans+=solve(i)+;
printf("%d\n",ans);
return ;
}
CF51F Caterpillar (边双+树形DP)的更多相关文章
- hdu 4612 Warm up 双连通+树形dp思想
Warm up Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others) Total S ...
- HDU5739 Fantasia 树形dp + 点双缩点
这个题当时打多校的时候有思路,但是代码能力差,没有写出来 事后看zimpha巨巨的题解,看了觉得基本差不多 核心思路:就是找出割点,然后变成森林,然后树形dp就可以搞了 关键就在重新构图上,缩完点以后 ...
- HDU4612(Warm up)2013多校2-图的边双连通问题(Tarjan算法+树形DP)
/** 题目大意: 给你一个无向连通图,问加上一条边后得到的图的最少的割边数; 算法思想: 图的边双连通Tarjan算法+树形DP; 即通过Tarjan算法对边双连通缩图,构成一棵树,然后用树形DP求 ...
- HDU 2242 考研路茫茫—空调教室 (边双连通+树形DP)
<题目链接> 题目大意: 给定一个连通图,每个点有点权,现在需要删除一条边,使得整张图分成两个连通块,问你删除这条边后,两联通块点权值和差值最小是多少. 解题分析: 删除一条边,使原连通图 ...
- hdu 2242双联通分量+树形dp
/*先求出双联通缩点,然后进行树形dp*/ #include<stdio.h> #include<string.h> #include<math.h> #defin ...
- poj3162 树形dp|树的直径 + 双单调队列|线段树,好题啊
题解链接:https://blog.csdn.net/shiqi_614/article/details/8105149 用树形dp是超时的,, /* 先求出每个点可以跑的最长距离dp[i][0|1] ...
- 51nod 1812 树的双直径 题解【树形DP】【贪心】
老了-稍微麻烦一点的树形DP都想不到了. 题目描述 给定一棵树,边权是整数 \(c_i\) ,找出两条不相交的链(没有公共点),使得链长的乘积最大(链长定义为这条链上所有边的权值之和,如果这条链只有 ...
- 【BZOJ-3572】世界树 虚树 + 树形DP
3572: [Hnoi2014]世界树 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1084 Solved: 611[Submit][Status ...
- [SHOI2008]仙人掌图 II——树形dp与环形处理
题意: 给定一个仙人掌,边权为1 距离定义为两个点之间的最短路径 直径定义为距离最远的两个点的距离 求仙人掌直径 题解: 类比树形dp求直径. f[i]表示i向下最多多长 处理链的话,直接dp即可. ...
随机推荐
- Java设计模式菜鸟系列(一)策略模式建模与实现
转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/39721563 今天開始咱们来谈谈Java设计模式. 这里会结合uml图形来解说,有对uml ...
- 深圳MPD大会 讲师演讲稿 2014-10
深圳MPD大会 讲师演讲稿 2014-10 互联网下的蛋-姜志辉.pdf: http://www.t00y.com/file/76704370 俞炜-互联网研发整形术 终于版.pdf: htt ...
- 通达OA 小飞鱼老师OA工作流设计课程教学网络公开课之HTML基础(一)
通达OA网络教学公开课開始了.有须要的小伙伴们抓住机会奥. 8月29号晚8点不见不散.本次课程的主要内容是通达OA工作流设计课程中须要用到的Html部分学习. 帮忙转发的朋友加送一节VIP课程.
- apt --fix-broken install
1 自动修复安装出现broken的package 但是,如果还是失败的话,就需要手动进行干预了.
- Ip获取请求ip
public class IPAdress { public static bool isIP(string str1) { || str1.Length > ) return false; s ...
- Java —— 正则表达式
0. 注意 正则表达式里的点号(.),可以匹配除换行符之外的所有字符 Java 语言同其他语言中的正则表达式的不同在于: 对 \(反斜线)的不同处理 \\:其他语言中,表示在正则表达式中插入普通的反斜 ...
- C#窗体间传值的简便方法/工具
一.问题:窗体间传值必须需要窗体之间有联系,具体有如下方式 窗体间传值涉及到窗体A必须拥有窗体B,这样才可以实现A-B之间传值 窗体A与窗体B在窗体/实例C中,A-B可互相通讯 其他方式,不细讨论,复 ...
- pcntl研究
虽说php用于并发计算有点山寨,但总比没有强把.(有问题请指正) 下面是pcntl多线程的例子.(只能用于cli模式,而且只能用于linux环境) <?php $starttime=microt ...
- [Apple开发者帐户帮助]九、参考(1)证书类型
该证书类型有助于开发者帐户和Xcode的标识证书. 类型 目的 APNs Auth Key 生成服务器端令牌,以替代通知请求的证书. Apple推送服务 在通知服务和APN之间建立连接,以向您的应用提 ...
- [Apple开发者帐户帮助]七、注册设备(1)注册一个设备
您需要已注册的设备来创建开发或临时配置文件.要使用开发人员帐户注册设备,您需要拥有设备名称和设备ID. 注意:如果您使用自动签名,Xcode会为您注册连接的设备.Xcode Server也可以配置为注 ...