zoukankan      html  css  js  c++  java
  • UVALive 6515

    题意:给定一棵带边权的树,求从任意一点出发,访问不同的n-k个点,然后回到起点的最小边权和。

    这题在PKUSC中考到了,当时大概有一半的人A了,我当时感觉毫无思路...回家后又冷静的想了想,然后就搞出来了,感觉思路还是很妙的吧..

    首先我们考虑如果要访问所有的点,那答案显然是边权和的2倍,那么现在只要访问n-k个点,那么我们就容易想到找一个边权和最小的,包含n-k个点的连通块,那么答案就是这个连通块边权和的2倍。那么我们怎么找呢,我最初想到的是按照kruscal的算法,按边权从小到大加边,用并查集维护一下块的大小,当超过n-k后再删除一些点,后来感觉这样搞的正确性无法保证,因为删除的时候是有限制的,只能删除度为1的点,否则连通性就会被破坏,这样就不一定保证最优了。

    那么既然我们考虑加边不好搞,而且刚刚已经发现了删边的条件,那么我们就可以考虑从这棵树中删去一些边,使其成为包含n-k个点的连通块,我们每次选取一个度为1的,连的边权最大的点删掉,然后更新一下其他点的度,重复k次,这样就得到了那个连通块,答案即为边权和乘2

    upd: 发现自己做法是错的,这数据也太水了..这样做的问题是如果有一个边权特别大,但它的度不是一,那么我们如果能删掉这条边就删掉这条边,但上述贪心不一定会这么做...正确的做法应该是树形DP,dp[i][j]表示以i为根的子树删了j个点的最小权值和,然后转移一波就可以了。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<queue>
     5 using namespace std;
     6 #define maxn 20005
     7 typedef long long LL;
     8 int pre[maxn],last[maxn],other[maxn],len[maxn];
     9 int n,k,T,l,du[maxn];
    10 LL ans;
    11 bool flag[maxn];
    12 struct Vergil
    13 {
    14     int x,key;
    15     bool operator < (const Vergil &a) const 
    16     {
    17         return key<a.key;
    18     }
    19 };
    20 priority_queue<Vergil> Q;
    21 
    22 inline int read(void)
    23 {
    24     int x=0;
    25     char ch=getchar();
    26     while (ch>'9'||ch<'0') ch=getchar();
    27     while (ch>='0'&&ch<='9')
    28     {
    29         x=x*10+ch-'0';
    30         ch=getchar();
    31     }
    32     return x;
    33 }
    34 
    35 void connect(int x,int y,int z)
    36 {
    37     l++;
    38     pre[l]=last[x];
    39     last[x]=l;
    40     other[l]=y;
    41     len[l]=z;
    42 }
    43 
    44 int main()
    45 {
    46     T=read();
    47     while (T--) 
    48     {
    49         n=read();k=read();
    50         memset(flag,0,sizeof flag);
    51         memset(last,0,sizeof last);
    52         memset(du,0,sizeof du);
    53         ans=l=0;
    54         for (int i=1;i<n;i++) 
    55         {
    56             int x=read(),y=read(),z=read();
    57             x++;y++;
    58             ans+=z;
    59             connect(x,y,z);
    60             connect(y,x,z);
    61             du[x]++;du[y]++;
    62         }
    63         while (!Q.empty()) Q.pop();
    64         for (int i=1;i<=n;i++) 
    65             if (du[i]==1) 
    66                 for (int p=last[i];p;p=pre[p])
    67                     Q.push((Vergil){i,len[p]});
    68         while (k--) 
    69         {
    70             Vergil tmp=Q.top();Q.pop();
    71             ans-=tmp.key;
    72             int u=tmp.x;flag[u]=1;
    73             for (int p=last[u];p;p=pre[p])
    74             {
    75                 int v=other[p];
    76                 if (flag[v]) continue;
    77                 du[v]--;
    78                 if (du[v]==1) 
    79                     for (int P=last[v];P;P=pre[P])
    80                         if (!flag[other[P]]) Q.push((Vergil){v,len[P]});
    81             }
    82         }
    83         printf("%lld
    ",ans*2);
    84     }
    85     return 0;
    86 }
  • 相关阅读:
    scala言语基础学习七
    scala言语基础学习六
    scala言语基础学习五
    scala言语基础学习四
    scala言语基础学习三(面向对象编程)
    scala言语基础学习三
    scala言语基础学习二
    scala言语基础学习
    并发编程实战的阅读(锁的重入)
    数据库必会必知 之 SQL四种语言:DDL DML DCL TCL(转)
  • 原文地址:https://www.cnblogs.com/lvyouyw/p/6897426.html
Copyright © 2011-2022 走看看