POJ 3013 Big Christmas Tree

Big Christmas Tree

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 ve (0 ≤ ve ≤ 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 abc 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

题目描述大概是这样:

KCm要准备一颗圣诞树,这棵树有一些节点和边组成。节点从1到n,根总是1.每个节点都有自己的总量,而边的价格是由边的单价乘以子孙节点的重量。

求出这么一颗有n个节点的树,使花费最小。

这个题POJ上交了30次,终于AC了,留下了属于蒟蒻的泪水,哭哭。

首先,这个样例很是苟啊,蒟蒻看了40分钟才知道它在干嘛

如上图所示

样例2

ans=4*40+3*50+2*60+3*(20+40+50+60)+2*30+1*(10+20+30+40+50+60)=1210;

但是......

真的是这样算吗???

一通模拟?

其实是道小学数学题

将上式去括号,用提公因式的方法整理,ans=40*(4+3+1)+50*(3+3+1)+60*(2+3+1)+30*(2+1)+20*(3+1)+10*1=1210;

观察发现

这不就是每个点权重weight[i]*dis[i](每个点到根节点的最短路)吗??

于是

上代码

1.迪杰特斯拉(堆优化)

  1 //djs
  2 #include<cstdio>
  3 #include<iostream>
  4 #include<queue>
  5 #include<cstring>
  6 using namespace std;
  7 int t;
  8 int n,m;
  9 int weight[100005];
 10 int u,v,w;
 11 struct edge
 12 {
 13     int to;
 14     int nxt;
 15     int val;
 16 }a[1000010];
 17 struct dian
 18 {
 19     int h;
 20     int s;
 21 };
 22 int head2[100005],tot;
 23 void add(int u,int v,int w)
 24 {
 25     a[++tot].to=v;
 26     a[tot].val=w;
 27     a[tot].nxt=head2[u];
 28     head2[u]=tot;
 29 }
 30 long long dis[100010];
 31 priority_queue<dian> q;
 32 bool operator <(dian b,dian c)
 33 {
 34     return b.s>c.s;
 35 }
 36 bool vis[100010];
 37 void djs()
 38 {
 39     while(!q.empty()) q.pop();
 40     q.push(dian{1,0});
 41     dis[1]=0;
 42     while(!q.empty())
 43     {
 44         dian x=q.top();
 45         q.pop();
 46         if(!vis[x.h])
 47         {
 48             for(int i=head2[x.h];i;i=a[i].nxt)
 49             {
 50                 int ww=a[i].val,vv=a[i].to;
 51                 if(!vis[a[i].to]&&dis[vv]>dis[x.h]+ww)
 52                 {
 53                     dis[vv]=dis[x.h]+ww;
 54                     q.push(dian{a[i].to,dis[a[i].to]});
 55                 }
 56             }
 57         }    
 58     }
 59     bool flag=true;
 60     long long ans=0;
 61     for(int i=2;i<=n;i++)
 62     {
 63         if(dis[i]==10000000000000)
 64         {
 65             flag=false;
 66             break;
 67         }
 68         ans+=dis[i]*weight[i];
 69     }
 70     if (!flag)
 71     {
 72         printf("No Answer\n");
 73     }
 74     else
 75         printf("%lld\n", ans);
 76 }
 77 int main()
 78 {
 79     cin>>t;
 80     while(t--)
 81     {
 82         scanf("%d%d", &n, &m);
 83         for(int i=1;i<=n;i++)
 84         {
 85             vis[i]=false;
 86             a[i].nxt=0;
 87             a[i].to=0;
 88             a[i].val=0;
 89             head2[i]=0;
 90             dis[i]=10000000000000;
 91         }
 92         for(int i=1;i<=n;i++)
 93         scanf("%d", &weight[i]);
 94         tot=0;
 95         for(int i=1;i<=m;i++)
 96         scanf("%d%d%d", &u, &v, &w),add(u,v,w),add(v,u,w);
 97         if (n == 0 || n == 1)
 98         {
 99             printf("0\n");
100             continue;
101         }
102         djs();
103     }
104     return 0;
105 }

 2.手写队列SPFA

 1 //spfa
 2 #include<cstdio>
 3 #include<iostream>
 4 #include<queue>
 5 #include<cstring>
 6 using namespace std;
 7 int t;
 8 int n,m;
 9 int weight[100005];
10 int u,v,w;
11 struct edge
12 {
13     int to;
14     int nxt;
15     int val;
16 }a[1000010];
17 int head[100005],tot;
18 void add(int u,int v,int w)
19 {
20     a[++tot].to=v;
21     a[tot].val=w;
22     a[tot].nxt=head[u];
23     head[u]=tot;
24 }
25 long long dis[100010];
26 int q[20*50005];
27 bool vis[100010];
28 void spfa()
29 {
30     int head2=0,tail=1;
31     q[1]=1;
32     vis[1]=true;
33     dis[1]=0;
34     while(head2<=tail)
35     {
36         int x=q[head2];
37         head2++;
38         vis[x]=false;
39         for(int i=head[x];i;i=a[i].nxt)
40         {
41             int ww=a[i].val,vv=a[i].to;
42             if(dis[vv]>dis[x]+ww)
43             {
44                 dis[vv]=dis[x]+ww;
45                 if(vis[vv]) continue;
46                 vis[vv]=true;
47                 tail++;
48                 q[tail]=vv;
49             }
50         }
51     }
52     bool flag=true;
53     long long ans=0;
54     for(int i=2;i<=n;++i)
55     {
56         if(dis[i]==10000000000000)
57         {
58             flag=false;
59             break;
60         }
61         ans+=dis[i]*weight[i];
62     }
63     if (!flag)
64     {
65         printf("No Answer\n");
66     }
67     else
68         printf("%lld\n", ans);
69 }
70 int main()
71 {
72     cin>>t;
73     while(t--)
74     {
75         scanf("%d%d", &n, &m);
76         for(int i=1;i<=n;i++)
77         {
78             vis[i]=false;
79             a[i].nxt=0;
80             head[i]=0;
81             dis[i]=10000000000000;
82             q[i]=0;
83         }
84         for(int i=1;i<=n;i++)
85         scanf("%d", &weight[i]);
86         tot=0;
87         for(int i=1;i<=m;i++)
88         scanf("%d%d%d", &u, &v, &w),add(u,v,w),add(v,u,w);
89         if (n == 0 || n == 1)
90         {
91             printf("0\n");
92             continue;
93         }
94         spfa();
95     }
96     return 0;
97 }

愉快结束。

转载于:https://www.cnblogs.com/oierglh/p/10484112.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值