(最短路)POJ 3013 - Big Christmas Tree

题意:

有一张有权无向图,编号1的点为根,要求一个生成树,使得总花费sum(每条边的花费×子树所有节点花费的和)最小,输出这个值。

 

分析:

自己想了半天,永远离不开生成树上面,因为之前知道这个题是用最短路做的,想了半天也想不通为什么会是用最大路做的。

如果放在现场,自己肯定做不出来。

其实这题主要的思想转化在于sum(每条边的花费×子树所有节点花费的和)这个公式。

这个公式其实是等价于sum(每条点的花费×该点到根的边花费的和)。

稍微想想就能明白了。

其他的已经没什么难度了,无非是最短路而已。

不过这题有坑,按道理n==0应该是输出No Answer。

因为:

树状图是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合

不过也发现自己的思维真的很江化,算了,慢慢来。

脑子不够就用经验凑。

 

代码:

 

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <queue>
  5 #include <vector>
  6 
  7 
  8 using namespace std;
  9 
 10 typedef  long long ll;
 11 const ll inf = 1ll<<60;
 12 const int maxn=50010;
 13 
 14 
 15 int t;
 16 int n,m;
 17 ll pa[maxn];
 18 
 19 struct Edge {
 20     int v;
 21     ll c;
 22 };
 23 
 24 struct Node {
 25     int v;
 26     ll c;
 27     Node(int _v,ll _c) {
 28         v=_v,c=_c;
 29     }
 30     bool operator<(const Node &a)const {
 31         return c>a.c;
 32     }
 33 };
 34 
 35 
 36 vector<Edge> edge[maxn];
 37 bool vis[maxn];
 38 ll dist[maxn];
 39 
 40 bool dijkstra(int n,int s) {
 41     memset(vis,false,sizeof(vis));
 42     for(int i=1; i<=n; i++)dist[i]=inf;
 43     priority_queue<Node> pq;
 44     while(!pq.empty())pq.pop();
 45     dist[s]=0;
 46     pq.push(Node(s,0));
 47     int cnt=0;
 48     while(!pq.empty()) {
 49         Node tmp = pq.top();
 50         pq.pop();
 51         int u=tmp.v;
 52         if(vis[u])continue;
 53         cnt++;
 54         vis[u]=true;
 55         for(int i=0; i<edge[u].size(); i++) {
 56             int v = edge[u][i].v;
 57             ll c = edge[u][i].c;
 58             if(!vis[v]&&dist[v]>dist[u]+c) {
 59                 dist[v]=dist[u]+c;
 60                 pq.push(Node(v,dist[v]));
 61             }
 62         }
 63     }
 64     return cnt>=n;
 65 }
 66 
 67 int main() {
 68     scanf("%d",&t);
 69     while(t--) {
 70         for(int i=0; i<=n; i++) {
 71             edge[i].clear();
 72         }
 73         scanf("%d%d",&n,&m);
 74         for(int i=1; i<=n; i++) {
 75             scanf("%lld",&pa[i]);
 76         }
 77         for(int i=0; i<m; i++) {
 78             int u,v;
 79             ll c;
 80             scanf("%d%d%lld",&u,&v,&c);
 81             edge[u].push_back(Edge{v,c});
 82             edge[v].push_back(Edge{u,c});
 83         }
 84         if(n<=1) {
 85             puts("0");
 86             continue;
 87         }
 88         if(dijkstra(n,1)) {
 89             ll ans=0;
 90             for(int i=2; i<=n; i++) {
 91                 ans+=dist[i]*pa[i];
 92             }
 93             printf("%lld\n",ans);
 94         } else {
 95             puts("No Answer");
 96         }
 97 
 98     }
 99 
100 
101     return 0;
102 
103 }

 

转载于:https://www.cnblogs.com/tak-fate/p/6750515.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值