A - Big Christmas Tree POJ - 3013 (最短路)

Big Christmas Tree

Time Limit: 3000MS Memory Limit: 131072K
Total Submissions: 28847 Accepted: 6285
Description

Christmas is coming to KCM city. Suby the loyal civilian in KCM city is preparing a big neat Christmas tree. The simple structure of the tree is shown in right picture.

在这里插入图片描述

The tree can be represented as a collection of numbered nodes and some edges. The nodes are numbered 1 through n. The root is always numbered 1. Every node in the tree has its weight. The weights can be different from each other. Also the shape of every available edge between two nodes is different, so the unit price of each edge is different. Because of a technical difficulty, price of an edge will be (sum of weights of all descendant nodes) × (unit price of the edge).

Suby wants to minimize the cost of whole tree among all possible choices. Also he wants to use all nodes because he wants a large tree. So he decided to ask you for helping solve this task by find the minimum cost.

Input

The input consists of T test cases. The number of test cases T is given in the first line of the input file. Each test case consists of several lines. Two numbers v, e (0 ≤ v, e ≤ 50000) are given in the first line of each test case. On the next line, v positive integers wi indicating the weights of v nodes are given in one line. On the following e lines, each line contain three positive integers a, b, c indicating the edge which is able to connect two nodes a and b, and unit price c.

All numbers in input are less than 216.

Output

For each test case, output an integer indicating the minimum possible cost for the tree in one line. If there is no way to build a Christmas tree, print “No Answer” in one line.

Sample Input

2
2 1
1 1
1 2 15
7 7
200 10 20 30 40 50 60
1 2 1
2 3 3
2 4 2
3 5 4
3 7 2
3 6 3
1 5 9
Sample Output

15
1210

题意:
树可以表示为一组编号的节点和一些边。节点编号从1到n。根节点的编号总是1。树中的每个节点都有自己的权值。权重可以是不同的。而且两个节点之间每条可用边的形状不同,所以每条边的单价也不同。由于技术上的困难,一条边的价格为(所有后代节点的权值之和)x(边的单价)。Suby希望在所有可能的选择中最小化整棵树的成本。他还想使用所有节点,因为他想要一个大的树。所以他决定请你帮他解决这个问题,方法是找出最小的花费。如果构不成树输出“No Answer” 。

思路:
根据题意,既然要找出花费最小的树,每个点还必须都在树上且每个点的权值都固定了,所以我们和不考虑,让这棵树的每个边的权值最小呢,那这样我们就画出来了样例树,上图:
在这里插入图片描述
我们可以看到,我们放弃了 1-5-9 这条边,这样我们就可以根据题意:一条边的价格为(所有后代节点的权值之和)x(边的单价)。列出式子,上图:
在这里插入图片描述
我们很容易列出等号之前的式子,但是我们会发现,我们对这个式子的代码实现就成了问题,但是这个式子肯定是对的,所以我就想在这个式子上化简合并同类项一下,看看能不能有所收获,当我化简到 50 的时候,我就不经意的看了一下括号里的,又看了一下上图的树,发现,这题原来想考察的是最短路呀,这不就是每个顶点的权值 × 每个顶点到起点的最短路径 再做和嘛。

上代码:

这种方法有点慢,题目限制的是3秒,这代码,emmmm…
在这里插入图片描述

//vactor 模拟邻接矩阵实现

#include<cstdio>
#include<cstring>
#include<queue>

#define INF 1e12

using namespace std;
typedef long long ll;


const int MAX = 5e4+10;

struct edge{
	int to,w;
	//边:起点 from ,终点 to,权值 w ,from 并没有用到, e[i] 的 i 就是 from  
};

vector<edge>e[MAX];  // e[i] : 存第 i 个节点连接的所有边   此时的 i 就是起点,所以我把结构体里面的from给删了  
int n,m;
ll aa[MAX];       //存每个节点的权值 


int spfa(int s){
	
	ll dis[MAX];     //记录所有结点到起点的距离 
	bool inq[MAX];    //inq[i] = true 表示节点 i 在队列中 

	for(int i = 1; i <= n; i++){  //初始化 
		dis[i] = INF;
		inq[i] = false;
	}
	dis[s] = 0;    //起点到自己的距离是 0  
	queue<int>Q;
	while(!Q.empty()) Q.pop(); 
	Q.push(s);
	inq[s] = true;   //起点入队列
	while(!Q.empty()){
		int u = Q.front();
		Q.pop();   //队列出队
		inq[u] = false;
		for(int i = 0; i < e[u].size(); i++){    //检查节点 u 的所有邻居 
			int v = e[u][i].to,w = e[u][i].w;
			if(dis[u] + w < dis[v]){ //u 的第 i 个邻居 v, 他借道 u 到 s 更近      
				dis[v] = dis[u] + w;  //更新第 i 个邻居到 s 的距离           
				if(!inq[v]){  //第 i 个邻居更新状态了,但是他不在队列中,把它放进队列 
					inq[v] = true;  
					Q.push(v);

				} 
			} 
		}  
	}
	
	int flag = 0;
	for(int i = 1; i <= n; i++){
		if(dis[i] == INF){
			flag = 1;
			break;			
		}
	}
	if(flag == 1){
		printf("No Answer\n");
	}
	else{
		ll sum = 0;
		for(int i = 1; i <= n; i++){
			sum += dis[i]*aa[i];
		}
		printf("%lld\n",sum);
	}     
	return 0; 
}

int main(){
	int T,a,b,c; 
	scanf("%d",&T);
	
	while(T--){
		scanf("%d %d",&n,&m);
		for(int i = 1; i <= n; i++){
			e[i].clear();
		}
		for(int i = 1; i <= n; i++){
			scanf("%lld",&aa[i]);
		}
		for(int i = 1; i <= m; i++){
			scanf("%d %d %d",&a,&b,&c);
			e[a].push_back( (edge) {b,c} ); //结点 a 的邻居,都放在 node[a] 里 
			e[b].push_back( (edge) {a,c} );
		} 
		spfa(1);   //起点是1 
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值