其实省选在四天前就已经结束了,但由于题目难度略大我到今天上午才补完所有题目……(捂脸逃)考场上很幸运,打完了所有我会写的部分分,最后Round1的110分 + Round2的70分,勉强算是没有被联赛day2的文件夹坑太多。。。

    目前网上比较容易找到的题解似乎只有ydc教主的这份:http://ydc.blog.uoj.ac/blog/336,不过对于我这种水平的人来说这份题解还不是很好理解,那么我再来稍微补充一点更基础的内容吧。。

    有一棵点数为N的树,树边有边权。给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染成白色。将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间距离的和的收益。问收益最大值是多少。

    其中$1 \leq N \leq 2000, 0 \leq K \leq N$。

分析.

     从点和点的距离入手不太好分析……我在考场上想了一两个小时最后还是弃疗了,连暴力都没心情写,交了一份靠运气的贪心骗分。

     其实呢……由于树上每一条边都是桥,我们可以从每一条边两端的黑白点数入手,也就是考虑每条边对答案造成的贡献。定义函数f(v, i)表示在v子树中,共将i个点染色后,能得到的“子树中所有点的父边的对答案的贡献之和”的最大值。这样每棵子树就成了一个可分割的子结构,就可以做树形背包了。

     根据官方题解中给出的那种神奇的证明,这样做的时间复杂度是$O(N^2)$.

代码.

 1 /***********************************************************************/
 2 /**********************By Asm.Def-Wu Jiaxin*****************************/
 3 /***********************************************************************/
 4 #include 
 5 #include 
 6 #include 
 7 #include 
 8 #include 
 9 #include 
10 using namespace std;
11 #define SetFile(x) ( freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout) );
12 #define UseFREAD
13 #ifdef UseFREAD
14 #define getc() *(file_ptr++)
15 #define FreadLenth 5000000
16 char CHARPOOL[FreadLenth], *file_ptr = CHARPOOL;
17 #else
18 #define getc() getchar() 
19 #endif
20 #ifdef DEBUG
21 #include 
22 timeb SysTp;
23 #endif
24 template<class T>inline void getd(T &x){
25     char ch = getc();bool neg = false;
26     while(!isdigit(ch) && ch != '-')ch = getc();
27     if(ch == '-')ch = getc(), neg = true;
28     x = ch - '0';
29     while(isdigit(ch = getc()))x = x * 10 - '0' + ch;
30     if(neg)x = -x;
31 }
32 /***********************************************************************/
33 const int maxn = 2003;
34 typedef long long LL;
35 #include 
36 struct Edge{int to, w;};
37 vector adj[maxn];
38 
39 LL f[maxn][maxn], S[maxn][maxn];
40 int N, K, size[maxn];
41 
42 inline void UPD(LL &a, const LL &b){if(a < b)a = b;}
43 
44 void dfs(int cur, int p, int w){
45     vector::iterator it;
46     int i, j, to;
47     size[cur] = 1;
48     for(it = adj[cur].begin();it != adj[cur].end();++it)if((to = (*it).to) != p){
49         dfs(to, cur, (*it).w);
50         for(i = min(size[cur], K);i >= 0;--i)for(j = min(size[to], K - i);j >= 0;--j)
51             UPD(S[cur][i + j], S[cur][i] + f[to][j]);
52         size[cur] += size[to];
53     }
54     for(i = size[cur];i >= 0;--i)
55         f[cur][i] = S[cur][i] + (LL)w * (i * (K - i) + (N - K - size[cur] + i) * (size[cur] - i));
56 }
57 
58 inline void work(){
59     getd(N), getd(K);
60     int i, a, b, c;
61     for(i = 1;i < N;++i){
62         getd(a), getd(b), getd(c);
63         adj[a].push_back((Edge){b, c});
64         adj[b].push_back((Edge){a, c});
65     }
66     dfs(100);
67     printf("%lld\n", f[1][K]);
68 }
69 
70 int main(){
71 
72 #ifdef DEBUG
73     freopen("test.txt""r", stdin);ftime(&SysTp);
74     size_t Begin_sec = SysTp.time, Begin_mill = SysTp.millitm;
75 #elif !defined ONLINE_JUDGE
76     SetFile(haoi2015_t1);
77 #endif
78 
79 #ifdef UseFREAD
80     fread(file_ptr, 1, FreadLenth, stdin);
81 #endif
82 
83     work();
84 
85 #ifdef DEBUG
86     ftime(&SysTp);
87     printf("\n%.3lf sec \n", (SysTp.time - Begin_sec) + (SysTp.millitm - Begin_mill) / 1000.0);
88 #endif
89     return 0;
90 }
树形背包

相关文章:

  • 2021-09-08
  • 2021-12-04
  • 2021-08-29
猜你喜欢
  • 2022-12-23
  • 2021-05-23
  • 2022-12-23
  • 2022-01-18
  • 2022-12-23
  • 2022-12-23
  • 2021-08-27
相关资源
相似解决方案