zoukankan      html  css  js  c++  java
  • NOIP 2007 树网的核

    题意

    哇,太长了。

    题解

    显然,树的直径不唯一但一定相交并且各个·直径的中点汇聚于同一处。

    进一步得到一个推论,任意一个直径上求出的偏心距都相等。

    原题中(n<=100)我们发现n的范围有点小。直接上暴力。

    floyed预处理一下。找到树的直径。

    暴力枚举树网的核再暴力枚举偏心距(至于具体怎么枚举看代码)

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<algorithm>
     6 using namespace std;
     7 int n,s,f[305][305],ans=999999999;
     8 int main(){
     9     scanf("%d%d",&n,&s);
    10     memset(f,0x3f,sizeof(f));
    11     for(int i=1;i<=n;i++){
    12         f[i][i]=0;
    13     }
    14     for(int i=1,u,v,w;i<=n-1;i++){
    15         scanf("%d%d%d",&u,&v,&w);
    16         f[u][v]=f[v][u]=w;
    17     }
    18     for(int x=1;x<=n;x++)
    19         for(int i=1;i<=n;i++)
    20             for(int j=1;j<=n;j++){
    21                 f[i][j]=min(f[i][j],f[i][x]+f[x][j]);
    22             }
    23     int l,r,maxx=0;
    24     for(int i=1;i<=n;i++)
    25         for(int j=1;j<=n;j++){
    26             if(f[i][j]>maxx){
    27                 maxx=f[i][j];
    28                 l=i;
    29                 r=j;
    30             }
    31         }
    32     for(int i=1;i<=n;i++)
    33         for(int j=1;j<=n;j++){
    34             if(f[i][j]<=s&&f[l][i]+f[i][j]+f[j][r]==f[l][r]){
    35                 int tmp=0;
    36                 for(int x=1;x<=n;x++){
    37                     tmp=max(tmp,(f[x][i]+f[x][j]-f[i][j])/2);
    38                 }
    39                 ans=min(ans,tmp);
    40             }
    41         }
    42     printf("%d",ans);
    43     return 0; 
    44 }
    View Code

    但是当(n<=300000 SDOI2011消防)时以上的做法就GG了。需要考虑更优的方法。
    考虑二分。(核越靠近中点答案越大)。对于我们二分的mid我们找到距离直径的两端距离大于等于mid的两点p,q之间的路径作为偏心距,判断是否成立即可。

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 using namespace std;
      5 #define N 300005
      6 
      7 int n,s,x,y,z,Max,dMax,pt,inf,ans;
      8 int tot,point[N],nxt[N*2],v[N*2],c[N*2];
      9 int h[N],father[N],edge[N],leaf[N],C[N],len[N],goal[N],dis[N];
     10 bool is[N];
     11 
     12 void add(int x,int y,int z)
     13 {
     14     ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;
     15 }
     16 void dfs(int x,int fa,int dep)
     17 {
     18     father[x]=fa;h[x]=dep;
     19     if (h[x]>Max)
     20     {
     21         Max=h[x],pt=x;
     22     }
     23     bool flag=false;
     24     for (int i=point[x];i;i=nxt[i])
     25         if (v[i]!=fa)
     26         {
     27             dfs(v[i],x,dep+c[i]),flag=true;
     28             edge[v[i]]=c[i];
     29         }
     30     if (!flag) leaf[++leaf[0]]=x;
     31 }
     32 void chain(int x)
     33 {
     34     while (h[x]!=0)
     35     {
     36         is[x]=true;
     37         C[++C[0]]=x;
     38         x=father[x];
     39     }
     40     C[++C[0]]=x;is[x]=true;
     41 }
     42 void length(int x,int fa,int dep,int st)
     43 {
     44     dis[st]=max(dis[st],dep);
     45     for (int i=point[x];i;i=nxt[i])
     46         if (v[i]!=fa&&!is[v[i]])
     47             length(v[i],x,dep+c[i],st);
     48 }
     49 bool check(int mid)
     50 {
     51     for (int i=1;i<=C[0];++i)
     52         if (dis[C[i]]<=mid) len[C[i]]=dis[C[i]]-mid;
     53         else return false;
     54 
     55     len[C[1]]=len[C[C[0]]]=mid;
     56     for (int i=1;i<=C[0];++i)
     57         if (len[C[i]]>=edge[C[i]])
     58         {
     59             len[C[i+1]]=min(len[C[i+1]],len[C[i]]-edge[C[i]]);
     60             len[C[i]]=inf;
     61         }
     62         else break;
     63     for (int i=C[0];i>=1;--i)
     64         if (len[C[i]]>=edge[C[i-1]])
     65         {
     66             len[C[i-1]]=min(len[C[i-1]],len[C[i]]-edge[C[i-1]]);
     67             len[C[i]]=inf;
     68         }
     69         else break;
     70     int l=0,a=0,b=0;
     71     for (int i=1;i<=C[0];++i)
     72         if (len[C[i]]!=inf) {a=i;break;}
     73     for (int i=C[0];i>=1;--i)
     74         if (len[C[i]]!=inf) {b=i;break;}
     75     for (int i=a;i<b;++i) l+=edge[C[i]];
     76     if (l<=s) return true;
     77     else return false;
     78 }
     79 int find()
     80 {
     81     int l=0,r=dMax,mid,ans;
     82     while (l<=r)
     83     {
     84         mid=(l+r)>>1;
     85         if (check(mid)) ans=mid,r=mid-1;
     86         else l=mid+1;
     87     }
     88     return ans;
     89 }
     90 int main()
     91 {
     92     scanf("%d%d",&n,&s);
     93     for (int i=1;i<n;++i)
     94     {
     95         scanf("%d%d%d",&x,&y,&z);
     96         add(x,y,z);add(y,x,z);dMax+=z;
     97     }
     98     dfs(1,0,0);
     99     leaf[0]=1,h[pt]=0,Max=0,edge[pt]=0,dfs(pt,0,0);
    100     chain(pt);
    101     memset(len,127,sizeof(len));inf=len[0];
    102     for (int i=1;i<=C[0];++i)
    103         length(C[i],0,0,C[i]);
    104     ans=find();
    105     printf("%d
    ",ans);
    106 }
    View Code
  • 相关阅读:
    TVM安装
    Caffe常用算子GPU和CPU对比
    [LeetCode] Longest Palindromic Substring 最长回文串
    [2019牛客多校第四场][G. Tree]
    [2019牛客多校第三场][G. Removing Stones]
    [2019HDU多校第一场][HDU 6580][C. Milk]
    [2019HDU多校第一场][HDU 6578][A. Blank]
    [2019HDU多校第一场][HDU 6590][M. Code]
    [2019HDU多校第一场][HDU 6588][K. Function]
    [2019牛客多校第二场][A. Eddy Walker]
  • 原文地址:https://www.cnblogs.com/Xu-daxia/p/9381489.html
Copyright © 2011-2022 走看看