POJ 3013 Big Christmas Tree(dijkstra算法堆优化模板)

题意:要建一棵圣诞树,使得总的花费最小。具体规则是:圣诞树是一颗无向树形图,其中,编号为1的节点为根节点,原始图中每条边具有边权(unit):材料的单位价值;每个点也有一个权(weight):点的重量。生成树中,各条边的花费是该边权(unit)* 该边的子树中所有点的重量(weight)和,总的花费则是生成树中所有边的花费之和。
分析:1、在树中,两点的路径是唯一的
         2、对点u,只有从点u到根结点之间的边会乘以点u的重量
           3、点u的重量不变
 结论:最小总花费=每条边(u,v)*v的子树中各结点的重量
                             =每个点的重量*从该点到根结点的每条边的单位价值
                             =每个点*该点到根结点的最短路

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
 
using namespace std;
const int maxn=50000+5;
const long long INF=0x3f3f3f3f3f;
int weight[maxn];
int cnt;
int head[maxn];
long long dis[maxn];
bool vis[maxn];
int n,m;
struct Edge
{
    int to,w,next;
} edge[maxn<<1];
 
struct Node
{
    int u,dis;
    // 此处的dis仅仅是为了使用优先队列:定义优先级
    bool operator <(const Node &a) const
    {
        return dis>a.dis;
        // 当返回true时会更新堆,因此当新元素a的dis小于堆顶元素dis
        // 的时候会返回true,同时会更新堆,故此堆为小顶堆
    }
};
void Init()
{
    cnt=0;
    memset(head,-1,sizeof(head));
    memset(vis,false,sizeof(vis));
    for(int i=0; i<=n; i++)
        dis[i]=INF;
}
void addEdge(int u,int v,int w)
{
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void Dijkstra(int s)
{
    Node now,next;
    priority_queue<Node>q;
    now.dis=0;
    now.u=s;
    dis[s]=0;
    q.push(now);
    while(!q.empty())
    {
        now=q.top();
        q.pop();
        if(vis[now.u])
            continue;
        int u=now.u;
        vis[u]=true;
        for(int i=head[u]; i!=-1; i=edge[i].next)
        {
            int to=edge[i].to;
            //对点v,会有多个dis存在,不过我们只取对顶元素,
            //即dis最小的点v
            if(!vis[to]&&dis[u]+edge[i].w<dis[to])
            {
                dis[to]=dis[u]+edge[i].w;
                next.dis=dis[to];
                next.u=to;
                q.push(next);
            }
        }
    }
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n>>m;
        Init();
        for(int i=1; i<=n; i++)
            scanf("%d",&weight[i]);
        int u,v,w;
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            addEdge(u,v,w);
            addEdge(v,u,w);
        }
        Dijkstra(1);
        long long sum=0;
        bool flag=true;
        for(int i=2; i<=n; i++)
        {
            if(dis[i]==INF)
            {
                flag=false;
                break;
            }
            sum+=dis[i]*weight[i];
        }
        if(flag)
            cout<<sum<<endl;
        else
            cout<<"No Answer"<<endl;
    }
    return 0;
}

 

posted @ 2018-08-12 21:44  Somnus、M  阅读(186)  评论(0编辑  收藏  举报