BZOJ1912 [Apio2010]patrol 巡逻

两次BFS求直径只能用于书上没有负权边的时候!树形DP求树的直径可以用于任何情况!

本题众所周知的解法是先求出第一次直径的长度,再将直径全变成1,再求一次直径。

第一次求直径用BFS,因为容易回溯出来直径;第二次求直径用树形DP,因为有负权边。

#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#include <cstdlib>
#include <stack>
#include <cstring>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define lep(i,a,b) for(int i=(a);i>=(b);i--) 
#define lepp(i,a,b) for(int i=(a);i>(b);i--)
#define pii pair<int,int>
#define pll pair<long long,long long>
#define mp make_pair
#define All(x) x.begin(),x.end() 
#define ms(a,b) memset(a,b,sizeof(a)) 
#define INF 0x3f3f3f3f
#define INFF 0x3f3f3f3f3f3f3f3f
#define multi int T;scanf("%d",&T);while(T--) 
using namespace std;
typedef long long ll;
typedef double db;
const int N=1e5+5;
const int mod=1e9+7;
const db eps=1e-6;                                                                            
const db pi=acos(-1.0);
int n,k,dis[N],pre[N],dp[N],vis[N],ans;
vector<pii>tr[N];
int bfs(int x){
    queue<int>q;
    while(q.size()) q.pop();
    q.push(x);
    ms(dis,0);
    ms(pre,0);
    pre[x]=-1;
    int pos=x;
    while(q.size()){
        int u=q.front();
        q.pop();
        for(int i=0;i<tr[u].size();i++){
            int v=tr[u][i].first,w=tr[u][i].second;
            if(pre[v]) continue;
            pre[v]=u;
            dis[v]=dis[u]+w;
            if(dis[v]>dis[pos]) pos=v;
            q.push(v);
        }
    }
    return pos;
}
int dfs(int u){
    vis[u]=1;
    for(int i=0;i<tr[u].size();i++){
        int v=tr[u][i].first,w=tr[u][i].second;
        if(vis[v]) continue;
        dfs(v);
        ans=max(ans,dp[u]+dp[v]+w);
        dp[u]=max(dp[u],dp[v]+w);
    }
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("D:\\work\\data.in","r",stdin);
    #endif
    cin>>n>>k;
    rep(i,1,n-1){
        int u,v;
        cin>>u>>v;
        tr[u].push_back(mp(v,1));
        tr[v].push_back(mp(u,1));
    }
    int p=bfs(1),q=bfs(p),l1=dis[q];
    if(k==1){
        cout<<2*(n-1)-l1+1<<endl;
        return 0;
    }
    while(q!=p){
        int bef=pre[q];
        for(int i=0;i<tr[bef].size();i++)
            if(tr[bef][i].first==q){
                tr[bef][i].second=-1;
                break;
            }
        for(int i=0;i<tr[q].size();i++)
            if(tr[q][i].first==bef){
                tr[q][i].second=-1;
                break;
            }
        q=bef;
    }
    ans=0;
    dfs(1);
    cout<<2*n-l1-ans<<endl;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值