您的位置:首页 > 其它

poj 4045 Power Station dfs求树上最小距离和

2015-03-27 23:45 351 查看
题意:

给一棵树,每条边的权值为R*I^2,求到所有其他节点权值和最小的点和相应最小权值和。

分析:

先将图转化成树,然后在树上dfs。

代码:

//poj 4045
//sep9
#include<iostream>
#include<vector>
using namespace std;
const int maxN=50012;
vector<int> g[maxN];
int vis[maxN],bro[maxN],son[maxN];
__int64 num[maxN],dis[maxN],dp[maxN];

int n,I,R;

void build_tree(int h)
{
	vis[h]=1;
	for(int i=g[h].size()-1;i>=0;--i){
		int x=g[h][i];
		if(vis[x]==0){
			vis[x]=1;
			bro[x]=son[h];
			son[h]=x;
			build_tree(x);	
		} 
	}
}

void dfs(int h,__int64& num_res,__int64& dis_res)
{
	num_res=1,dis_res=0;
	int s=son[h];
	while(s){
		__int64 x,y;
		dfs(s,x,y);
		num_res+=x;
		dis_res+=(x+y);
		s=bro[s];
	}
	num[h]=num_res;
	dis[h]=dis_res;	
}

void ex_dfs(int h,__int64 pre_sum)
{
	dp[h]=dis[h]+pre_sum;
	int s=son[h];
	while(s){
		__int64 a=n-num[s];
		__int64 b=dis[h]-(dis[s]+num[s])+pre_sum;
		ex_dfs(s,a+b);
		s=bro[s];
	}
} 

int main()
{
	int cases;
	scanf("%d",&cases);
	while(cases--){
		scanf("%d%d%d",&n,&I,&R);
		for(int i=1;i<=n;++i) g[i].clear();
		for(int i=1;i<n;++i){
			int a,b;
			scanf("%d%d",&a,&b);
			g[a].push_back(b);
			g[b].push_back(a);
		}
		memset(vis,0,sizeof(vis));
		memset(bro,0,sizeof(bro));
		memset(son,0,sizeof(son));
		build_tree(1);
		memset(num,0,sizeof(num));
		memset(dis,0,sizeof(dis));
		__int64 x,y;
		dfs(1,x,y);
		ex_dfs(1,0); 
		__int64 ans=dp[1];
		for(int i=1;i<=n;++i)
			ans=min(ans,dp[i]);
		printf("%I64d\n",ans*R*I*I);
		for(int i=1;i<=n;++i)
			if(dp[i]==ans)
				printf("%d ",i);
		printf("\n\n");
	}
	return 0;	
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: