(补题 POJ 3013) Big Christmas Tree

原题链接戳我~

题目描述

给你一个图,每个顶点和边都有权值。问能否构建出一棵树,如果能,请计算出代价最小的方案,如果不能请输出"-1"

代价的计算方法:所有边(该边的所有子节点的和( imes)该边的权值)的和(语文不好233333,只能解释到这了看不懂请看下面解题思路的样例~)

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

解题思路

最短路+注意数据过大以及INF需要开到超过0x3f3f3f3f

我们就拿样例中的第二组数来推导一下公式

通过样例我们不难看出,只需要删除1号点与5号点之间的9这条边然后进行建树 (如下图)

(1 imes(60+40+50+20+30+10)+2 imes30+3 imes(40+60+50)+4 imes40+2 imes60+3 imes50)

经过整理可得出(下角标为对应的节点编号)

(60_{(7)} imes(1+3+2)+40_{(5)} imes(1+3+4)+50_{(6)} imes(1+3+3)+20_{(3)} imes(1+3)+30_{(4)} imes(1+2)+10_{(2)} imes1+200_{(1)} imes0)

不难看出权值为每个店点到根节点1的最短路径乘上这个点的权值,加下来就要套用最短路的板子了,这个地方的最短路我用的是SPFA

代码样例

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

#define INF 1E16
using namespace std;

typedef long long ll;
bool visit[50005];
ll d[50005];
int head[50005];
int N,M;
int aa[50005];

struct node{
	int x,w,next;
}edge[150005];
int cnt = 0;
void add ( int u, int v, int w ) {
	edge[cnt].x = v, edge[cnt].w = w, edge[cnt].next = head[u]; head[u] = cnt++; 
}

void spfa()
{
	int i,k;
	queue<int>S;
	while(!S.empty())
	S.pop(); 
	memset(visit,0,sizeof(visit));
	for(i=2;i<=N;i++) d[i]=INF;
	d[1]=0;
	S.push(1);
	visit[1]=1;
	while(!S.empty()){
		k=S.front();
		S.pop();
		visit[k]=0;
		for(i=head[k]; i!=-1; i=edge[i].next){
			if(d[edge[i].x]>edge[i].w+d[k]){
				d[edge[i].x]=edge[i].w+d[k];
				if(!visit[edge[i].x]){
					S.push(edge[i].x);
					visit[edge[i].x]=1;
				}
			}
		}
	}
	int flag = 0;
	for(i = 1; i <= N; i++){
		if(d[i] == INF){
			flag = 1;
			break;			
		}
	}
	if(flag == 1){
		printf("No Answer
");
	}
	else{
		ll sum = 0;
		for(i = 1; i <= N; i++){
			sum += d[i]*aa[i];
		}
		printf("%lld
",sum);
	}     
}

int main()
{
	int T,x,w,v,i;
	scanf("%d",&T);
	while(T--){		
		scanf("%d %d",&N,&M);
		memset(head,-1,sizeof(head));
		
		for(i = 1; i <= N; i++){
			scanf("%lld",&aa[i]);
		}

		cnt = 0;
		for ( i = 1; i <= M; i++ ) {
			scanf("%d%d%d",&x,&w,&v);
			add( x, w, v );
			add( w, x, v );
		}

		// for(i=1;i<=M;i++){
		// scanf("%d%d%d",&x,&w,&v);
		// // edge[i].x = w, edge[i].w = v, edge[i].next = head[x]; head[x] = i; 
		// // edge[i].x=w;
		// // edge[i].w=v;
		// // edge[i].next=head[x];
		// // head[x]=i;
		// }

		spfa();
	}
return 0;
}
原文地址:https://www.cnblogs.com/cafu-chino/p/11759976.html