【BZOJ-1912】patrol巡逻 树的直径 + DFS(树形DP)

1912: [Apio2010]patrol 巡逻

Time Limit: 4 Sec  Memory Limit: 64 MB
Submit: 1034  Solved: 562
[Submit][Status][Discuss]

Description

Input

第一行包含两个整数 n, K(1 ≤ K ≤ 2)。接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ a, b ≤ n)。

Output

输出一个整数,表示新建了K 条道路后能达到的最小巡逻距离。

Sample Input

8 1
1 2
3 1
3 4
5 3
7 5
8 5
5 6

Sample Output

11

HINT

10%的数据中,n ≤ 1000, K = 1; 
30%的数据中,K = 1; 
80%的数据中,每个村庄相邻的村庄数不超过 25; 
90%的数据中,每个村庄相邻的村庄数不超过 150; 
100%的数据中,3 ≤ n ≤ 100,000, 1 ≤ K ≤ 2。

Source

Solution

发现加边实际上就是形成环,使得一条路径可以直接绕回来,不用原路返回

那么K==1的时候,边一定用来连最长的路径(树的直径)那么DFS出即可

K==2的时候同理,不过需要次短,同样DFS,对第一次DFS求得的路径做些修改,置成-1就可以

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
#define maxn 100010
int n,k,ans,zj,s;
struct EdgeNode{int next,to,len;}edge[maxn<<1];
int head[maxn],cnt=1;int road[maxn]={0},croad[maxn]={0};
void add(int u,int v,int w)
{
    cnt++;
    edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].len=w;
}
void insert(int u,int v,int w) {add(u,v,w); add(v,u,w);}
int DFS(int now,int fa)
{
    int maxd=0,cmaxd=0;
    for (int i=head[now]; i; i=edge[i].next)
        if (edge[i].to!=fa)
            {
                int len=DFS(edge[i].to,now)+edge[i].len;
                if (len>maxd) cmaxd=maxd,maxd=len,croad[now]=road[now],road[now]=i;
                else if (len>cmaxd) cmaxd=len,croad[now]=i;
            }
    if (maxd+cmaxd>zj) zj=maxd+cmaxd,s=now;
//    printf("%d %d %d %d\n",now,fa,maxd,cmaxd);
    return maxd;
}
int main()
{
    n=read(); k=read();
    for (int u,v,i=1; i<=n-1; i++) u=read(),v=read(),insert(u,v,1);
    DFS(1,0); ans=2*(n-1)-zj+1;
    if (k==2)
        {
            for (int i=road[s]; i; i=road[edge[i].to]) edge[i].len=edge[i^1].len=-1;
            for (int i=croad[s]; i; i=road[edge[i].to]) edge[i].len=edge[i^1].len=-1;
            zj=0; DFS(1,0); ans=ans-zj+1;
        }
    printf("%d\n",ans);
    return 0;
}

自己的代码写炸了,不知为何..

时间: 2024-09-29 22:08:02

【BZOJ-1912】patrol巡逻 树的直径 + DFS(树形DP)的相关文章

树的直径,树形DP,DFS——POJ1958

题目链接 题目含义 就是建一个树,让你求最大直径 下面用分别用DP和DFS的方法 题目代码 #include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int maxn=5e4+7; int n,m,tot,a,b,c,ans; char cc; int head[maxn],d[maxn]; struct node{ int to,w,next; }edge[ma

【HDOJ2196】Computer(树的直径,树形DP)

题意:给定一棵N个点树,询问这个树里面每个点到树上其他点的最大距离. n<=10000 思路:设f[u,1],f[u,2]为以U为根向下的最长与次长,g[u,1],g[u,2]为从哪个儿子转移来 第一次dfs用V更新U,第二次dfs用U更新V,因为有V向U往上走的情况,这样做就可以处理了 可以发现这些数值中取最大值就是树的直径了 1 var f,g:array[1..21000,1..2]of longint; 2 head,vet,next,len:array[1..21000]of long

bzoj 1912 : [Apio2010]patrol 巡逻 树的直径

题目链接 如果k==1, 显然就是直径. k==2的时候, 把直径的边权变为-1, 然后在求一次直径. 变为-1是因为如果在走一次这条边, 答案会增加1. 学到了新的求直径的方法... #include <bits/stdc++.h> using namespace std; #define pb(x) push_back(x) #define ll long long #define mk(x, y) make_pair(x, y) #define lson l, m, rt<<

bzoj 4871: [Shoi2017]摧毁“树状图”【树形dp】

做不来--参考https://www.cnblogs.com/ezyzy/p/6784872.html #include<iostream> #include<cstdio> using namespace std; const int N=100005; int T,o,n,h[N],cnt,f[N],g[N],q[N],q1[N],l[N],l1[N]; struct qwe { int ne,to; }e[N<<1]; int read() { int r=0,f

poj1655(dfs,树形dp)

方法:就记节点1为树的根,两次dfs,第一次求出每个节点的所有子孙再加上它自己的节点总数num[i].第二次就算出每个节点的balance值bal[i],算的时候就比较节点i它所有子节点的num值(删掉它之后以每个它的子节点为根形成一棵新树)还有n-num[i]的值(删掉i之后它的父节点及其相关节点也形成一棵新树),最大的就是bal[i]. 注意:WA了几次是因为没有考虑边界情况(n==2),dfs写的太不熟练了,代码能力有待提高啊! #include<iostream> #include&l

poj2378(dfs,树形dp)

和poj3107,poj1655一样的方法 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<map> #include<set> #include<vector> #include<algorithm> #include<stack> #inc

BZOJ 1907 树的路径覆盖 树形DP

题目大意:给定一棵树,求最小路径覆盖 数据范围1W,看到还想跑网络流来着= = 不过算了明明树形DP这么水还是不要用网络流这种大杀器为好 首先将所有的链都考虑成以链上所有点的LCA为转折点的V字形 那么点有两种:转折点和非转折点 因此我们选择两种状态进行转移:还会和父亲组成链的状态和成为转折点的状态 转移就自己YY算了 时间复杂度是线性的 #include <cstdio> #include <cstring> #include <iostream> #include

bzoj 4424: Cf19E Fairy &amp;&amp; codeforces 19E. Fairy【树形dp】

参考:https://blog.csdn.net/heheda_is_an_oier/article/details/51131641 这个找奇偶环的dp1真是巧妙,感觉像tarjan一样 首先分情况讨论,如果没有奇环,每条边都可以删:如果有一个奇环,奇环上隋边山:否则,删被所有奇环覆盖且没被任何一个偶环覆盖的边 那么重点就是怎样找到所有的奇环和偶环 用树形dp来搞,设f[i]记录经过第i条边的奇环数,g[i]记录经过第i条边的偶环数,因为是边的编号而存的是双向边,所以dp的时候用i>>1表示

[Bzoj 2427] [HAOI2010] 软件安装 tarjan缩点+树形DP

题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一 些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j).幸运的 是,一个软件最多依赖另外一个软件.如果一个软件不能正常工作,那么它能够发挥的作用为0. 我们现在知道了软件之间的依赖关系:软件i依赖软件Di.现在请你设计出