Factories Gym - 102222G(2018宁夏邀请赛暨2019银川icpc网络预选赛)

第一场icpc网络赛,出的去年宁夏邀请赛原题。c题还没有读完就有ak的了。。(滑稽)
Byteland has nn cities numbered from 11 to nn, and n−1n−1 bi-directional roads connecting them. For each pair of cities, the residents can arrive one from another one through these roads (which also means the road network in Byteland is a tree).

Ghaliyah, the queen of the land, has decided to construct kk new factories. To avoid contamination, she requires that a factory can locate at a city with only one road (which also means this city is a leaf in the road network). Besides, a city can only have one factory.

You, as the royal designer, are appointed to arrange the construction and meanwhile, minimize the sum of distances between every two factories.

Input
The input contains several test cases, and the first line is a positive integer TT indicating the number of test cases which is up to 103103.

For each test case, the first line contains two integers n (2≤n≤105)n (2≤n≤105) and k (1≤k≤100)k (1≤k≤100) indicating the number of cities in Byteland and the number of new factories which are asked to construct.

Each of the following n−1n−1 lines contains three integers u,v (1≤u,v≤n)u,v (1≤u,v≤n) and w (1≤w≤105)w (1≤w≤105) which describes a road between the city uu and the city vv of length ww.

We guarantee that the number of leaves in the road network is no smaller than kk, and the sum of nn in all test cases is up to 106106.

Output
For each test case, output a line containing Case #x: y, where x is the test case number starting from 11, and y is the minimum sum of distances between every two factories.

Example
Input
2
4 2
1 2 2
1 3 3
1 4 4
4 3
1 2 2
1 3 3
1 4 4
Output
Case #1: 5
Case #2: 18
题意,给一棵树,给出k各点,这k个点只能在叶子节点上,问着k个点到达其余各点的距离和最小值是多少。
树形dp。我们设定dp[x][i]代表着以x为祖先的子树有i个叶子节点的到达其余各点的最小距离。状态转移方程为dp[x][i]=min(dp[x][i],dp[x][i-j]+dp[son][j]+(k-j)*j *w)。其中son代表着x的子节点。注意到,dp[x][i]的转移与dp[x][i-j]相关,因此如果正着循环,可能会出现一个叶子节点多次更新一个父亲的情况。为了避免这个问题,可用常用套路,即利用一个辅助数组存储当前结果,到所有的转移都判断完毕后再重新复制给dp数组本身
代码如下:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x7f7f7f7f
using namespace std;

const int maxx=1e5+100;
struct edge{
	int to;
	int next;
	ll w;
}e[maxx<<1];
int head[maxx<<1],sze[maxx],d[maxx];
ll dp[maxx][101],lsd[maxx];
int n,k,tot;
/*-----------事前准备------------*/ 
inline void init()
{
	memset(head,-1,sizeof(head));
	for(int i=0;i<=n;i++) d[i]=0;
	for(int i=0;i<=n;i++)
	for(int j=0;j<=k;j++) dp[i][j]=1e18;tot=0;
}
inline void add(int u,int v,ll w)
{
	e[tot].to=v,e[tot].w=w,e[tot].next=head[u],head[u]=tot++;
}
/*-----------树形dp-----------*/
inline void dfs(int u,int f)
{
	if(d[u]==1)
	{
		dp[u][1]=dp[u][0]=0;
		sze[u]=1;
		return ;
	}
	sze[u]=0;dp[u][0]=0;
	for(int i=head[u];i!=-1;i=e[i].next)
	{
		int to=e[i].to;ll w=e[i].w;
		if(to==f) continue;
		dfs(to,u);
		sze[u]=min(sze[u]+sze[to],k);
		for(int i=0;i<=sze[u];i++) lsd[i]=1e18;
		for(int i=0;i<=sze[u];i++)
		{
			for(int j=0;j<=i&&j<=sze[to];j++)
			{
				lsd[i]=min(lsd[i],dp[u][i-j]+dp[to][j]+(k-j)*j*w);//!!!这里着重理解,要是用原值的话,会出错,因为有可能在这个值被用到之前就被更改了。所以要先存起来,最后再加上
			}
		}
		for(int i=0;i<=sze[u];i++) dp[u][i]=lsd[i];
	}
}
int main()
{
	int t,kk=0,x,y;ll w;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&k);init();
		for(int i=1;i<n;i++)
		{
			scanf("%d%d%lld",&x,&y,&w);
			add(x,y,w);
			add(y,x,w);
			d[x]++;d[y]++;
		}
		printf("Case #%d: ",++kk);
		if(k==1) printf("0\n");
		else if(n==2)
		{
			if(k==2) printf("%lld\n",w);
			else printf("0\n");
		}
		else
		{
			int i;
			for(i=1;d[i]==1;i++);
			dfs(i,0);
			printf("%lld\n",dp[i][k]);
		}
	}
	return 0;
}

努力加油a啊,(o)/~

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starlet_kiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值