zoukankan      html  css  js  c++  java
  • bzoj 1912: [Apio2010]patrol 巡逻

    Description

    solution

    正解:贪心+DP
    首先对于K=1的情况我们可以发现答案是 ((n-1)*2)-树的直径+1

    K=2同理,我们也要再找出一条不相交的树的直径,然后怎么保证不相交呢?
    其实只需要把第一次求得的直径上的点赋值为-1即可
    如果一条边再两次都出现,就相互抵消了,去掉抵消的部分,就完美的形成了不相交的两条链了,非常巧妙
    另外,两遍dfs求直径的方法在有负权的情况下是用不了了,需要DP求解,具体是记录最长链和次长链 相加

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    const int N=100005;
    int n,K,head[N],to[N<<1],nxt[N<<1],dis[N<<1],num=1;
    il void link(int x,int y,int z){
       nxt[++num]=head[x];to[num]=y;dis[num]=z;head[x]=num;}
    int f[N][2],ans=0,ansid=0,maxid[N],cmax[N];
    il void dfs(RG int x,int last){
       RG int u,tmp;
       for(int i=head[x];i;i=nxt[i]){
          u=to[i];if(u==last)continue;
          dfs(u,x);tmp=f[u][0]+dis[i];
          if(tmp>f[x][0])
             cmax[x]=maxid[x],maxid[x]=i,f[x][1]=f[x][0],f[x][0]=tmp;
          else if(tmp>f[x][1])f[x][1]=tmp,cmax[x]=i;
       }
       if(f[x][0]+f[x][1]>=ans)ans=f[x][0]+f[x][1],ansid=x;
    }
    il void Rev(int i){dis[i]=dis[i^1]=-1;}
    void solve(){
       Rev(maxid[ansid]);Rev(cmax[ansid]);
       RG int now=to[maxid[ansid]];
       while(maxid[now]){
          Rev(maxid[now]);
          now=to[maxid[now]];
       }
       now=to[cmax[ansid]];
       while(maxid[now]){
          Rev(maxid[now]);
          now=to[maxid[now]];
       }
    }
    void Clear(){
       memset(f,0,sizeof(f));memset(maxid,0,sizeof(maxid));
       memset(cmax,0,sizeof(cmax));ans=0;ansid=0;
    }
    void work()
    {
       int x,y,ret=0;
       scanf("%d%d",&n,&K);
       for(RG int i=1;i<n;i++){
          scanf("%d%d",&x,&y);
          link(x,y,1);link(y,x,1);
       }
       ret+=(n-1)<<1;dfs(1,1);ret-=ans-1;
       if(K==1){printf("%d
    ",ret);return ;}
       solve();Clear();dfs(1,1);ret-=ans-1;
       printf("%d
    ",ret);
    }
     
    int main()
    {
        work();
        return 0;
    }
    
  • 相关阅读:
    递归判断回文
    从小工到专家阅读笔记1
    建立SQL全文索引提升搜索速度
    数据库SQLServer经验小记
    [转]C#中调用SQL存储过程(带输入输出参数的例子)
    20101124 14:55 全文索引是解决海量数据模糊查询的较好解决办法
    使用SQL Server 2008提供的表分区向导
    千万级SQL Server数据库表分区的实现
    C#调用存储过程简单完整例子
    SQL server 海量数据库的查询优化及分页算法(收藏)
  • 原文地址:https://www.cnblogs.com/Hxymmm/p/7712761.html
Copyright © 2011-2022 走看看