RXD and dividing
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 2140 Accepted Submission(s): 912
Problem Description
RXD has a tree T, with the size of n. Each edge has a cost.
Define f(S) as the the cost of the minimal Steiner Tree of the set S on tree T.
he wants to divide 2,3,4,5,6,…n into k parts S1,S2,S3,…Sk,
where ⋃Si={2,3,…,n} and for all different i,j , we can conclude that Si⋂Sj=∅.
Then he calulates res=∑ki=1f({1}⋃Si).
He wants to maximize the res.
1≤k≤n≤106
the cost of each edge∈[1,105]
Si might be empty.
f(S) means that you need to choose a couple of edges on the tree to make all the points in S connected, and you need to minimize the sum of the cost of these edges. f(S) is equal to the minimal cost
Input
There are several test cases, please keep reading until EOF.
For each test case, the first line consists of 2 integer n,k, which means the number of the tree nodes , and k means the number of parts.
The next n−1 lines consists of 2 integers, a,b,c, means a tree edge (a,b) with cost c.
It is guaranteed that the edges would form a tree.
There are 4 big test cases and 50 small test cases.
small test case means n≤100.
Output
For each test case, output an integer, which means the answer.
Sample Input
5 4 1 2 3 2 3 4 2 4 5 2 5 6
Sample Output
27
题意:给你一棵无向带权树,你要把2~n号节点划分成k个部分。使每个部分并上1号节点的斯坦纳树值总和最大。
官方题解:
个人见解:不妨当成一个构造题。
首先 k=1就是所有边的权值和。
k=2,显然叶子结点划成一个集合,非叶节点划分成一个集合。这样答案最大。因为这样能使非叶节点的边数贡献增加到最大值。
k>=3时,我们取一颗子树u(以u为根的子树),考虑u的父边权值w的贡献。
假设子树大小为siz[u],若k>siz[u],我们显然可以每个节点划分成一部分,这是所有情况中最理想的情况。
如果有另一颗子树v,k也>siz[v](v在u内或者包含u就和上面一样,我们假设v不在u内且不包含u)
那么u,v两棵子树中的划分可以合并成max(siz[u],siz[v])个,并保持上述结果。
也就是说 无论多少颗互不包含的子树,若k>这些子树的size,那么一定可以划分成max(siz[i])部分,使w的贡献值达到最大。
若k<=siz[u] 除去本来就包含该节点的一次划分,我们考虑把其子树划分成k-1份。
无论怎么划分,w一定是贡献k次。(即按照子树刚才的那样过划分,能保持子树划分的贡献值不变)
因此dfs一遍,答案就是所有节点u的父边权值w*min(siz[v],k)的和。
好好想想上面的过程。有其他想法或者指正错误欢迎评论区留言。(因为我其实还不是想的很清楚)
代码:
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1000010;
const ll mo=1e9+7;
ll n,m,k,q,l,r;
struct node
{
ll v,w;
node();
node(ll q,ll o){v=q;w=o;}
};
vector<node>vc[maxn];
ll sum;
ll siz[maxn];
bool vis[maxn];
ll ans,ct,cnt,tmp,flag;
void dfs(ll u,ll fa,ll w)
{
siz[u]++;
for(int i=0;i<vc[u].size();i++)
{
node kk=vc[u][i];
if(kk.v==fa) continue;
dfs(kk.v,u,kk.w);
siz[u]+=siz[kk.v];
}
ans+=min(k,siz[u])*w;
}
int main()
{
int T,cas=1;
while(scanf("%lld%lld",&n,&k)!=EOF)
{
flag=1;ans=0;
int aa=0,bb=-1;
for(int i=1;i<=n;i++)
{siz[i]=0;vc[i].clear();}
for(int i=1;i<n;i++)
{
ll x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
vc[x].push_back(node(y,z));
vc[y].push_back(node(x,z));
}
ans=0;
dfs(1,-1,0);
printf("%lld\n",ans);
// if(flag) puts("Yes"); else puts("No");
}
return 0;
}
/*
999
5 2
1 2 3 4 5
3 2
2 1 3
*/