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
  • 相关阅读:
    HDOJ 4747 Mex
    HDU 1203 I NEED A OFFER!
    HDU 2616 Kill the monster
    HDU 3496 Watch The Movie
    Codeforces 347A A. Difference Row
    Codeforces 347B B. Fixed Points
    Codeforces 372B B. Hungry Sequence
    HDU 1476 Sudoku Killer
    HDU 1987 How many ways
    HDU 2564 词组缩写
  • 原文地址:https://www.cnblogs.com/Xu-daxia/p/9381489.html
Copyright © 2011-2022 走看看