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 }

愉快结束。

posted @ 2019-03-06 16:49  G_lh  阅读(161)  评论(1编辑  收藏  举报