poj 3013 Big Christmas Tree 最短路变形

题意:要建一棵圣诞树,使得总的花费最小。具体规则是:圣诞树是一颗无向树形图,其中,编号为1的节点为根节点,原始图中每条边具有边权:材料的单位价值;每个点也有一个权:点的重量。生成树中,各条边的花费是该边权* 该边的子树中所有点的重量和,总的花费则是生成树中所有边的花费之和。

题目要求是这样一棵树,每条边的权值是该边和所有子节点的点权和的乘积,那么,将我们的角度从边转移到点,对于每一个点,他所涉及的权值就是他延一条边到达源点1的距离*它本身的权值,对每个点都是如此;所以求出点1到每个点的单源最短路,每个点的距离乘点权和就是答案。

View Code
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
#define inf 1LL<<61
#define ll long long
const int maxn = 50050;
const int maxm = 500020;
struct Edge{
    int v,w,next;
}edge[maxm];
int E,head[maxn];
inline void init() { E=0; memset(head,-1,sizeof(head)); }
inline void addedge(int u,int v,int w) {
    edge[E].v=v;edge[E].w=w;edge[E].next=head[u];head[u]=E++;
    edge[E].v=u;edge[E].w=w;edge[E].next=head[v];head[v]=E++;
}
queue<int> Q;
bool mark[maxn];
ll dist[maxn];
int inque[maxn];
int n , m;
void spfa(int s){
   memset(mark,0,sizeof(mark));
   memset(inque,0,sizeof(inque));
   for(int i=1;i<=n;i++) dist[i]=inf;
   dist[s]=0;  mark[s]=true;  //inque[s]++;
   Q.push(s);
   int u,v,w;
   while(!Q.empty()){
       u=Q.front();Q.pop();
       mark[u]=false;
       for(int i=head[u];i!=-1;i=edge[i].next){
           v=edge[i].v;w=edge[i].w;
           if(dist[u]+w<dist[v]){
               dist[v]=dist[u]+w;
               if(!mark[v]){
                   mark[v]=true;
                   Q.push(v);
               }
           }
       }
   }
}
int weight[maxn];
int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d",&n,&m);
        init();
        for(int i=1;i<=n;i++) scanf("%d",&weight[i]);
        while(m--) {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
        }
        spfa(1);
        ll ret = 0;
        for(int i=1;i<=n;i++) {
            if(dist[i]==inf) { ret = -1; break; }
            ret += weight[i] * dist[i];
        }
        if(ret == -1) printf("No Answer\n");
        else cout<<ret<<endl;
    }
    return 0;
}
posted @ 2012-07-01 01:01  lenohoo  阅读(236)  评论(0编辑  收藏  举报