POJ 3013 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 v, e (0 ≤ v, e ≤ 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 a, b, c 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 }
愉快结束。