poj 3013 Big Christmas Tree
最近几天一直在做搜到的一些中级最短路题目,做得多了也有了一点感觉,觉得中等最短路一般不是建图麻烦些,就是松弛的条件要改变一下得到所求。其实了解透了几种最短路求解方法就很简单了。
解题过程:一颗有N个节点的树,点1是根节点,每个节点都有一个权值,每两个节点的边都有一个代价,定义一棵树的花费为每条边的代价为该边所有子孙节点权值之和乘以该边的权值。例如点1到点2的边的代价为w1,点2到点3的边的代价为w2,得出下面等式:
(d1+d2+d3)*w1 = d1*w1 + d2*w1 + d3*w1
(d1+d2+d3+d4)*w2 = d1*w2 + d2*w2 + d3*w2 + d4*w2
加起来的:sum = d1*(w1+w2) + d2 *(w1+w2) +d3*(w1+w2)+d4*w2 ;所以转化一下就可以得出每个节点的代价为该节点到根节点的所有边的权值乘以该节点的权值。
只要想清楚了这一点,这题就是一道裸地最短路题,数据较大,要用long long,Spfa求出。。。。。
第一次写完代码的时候,怎么都不对,将数组改成long long 也不对,又改了一下discuss里的各种注意,依然WA,有点恼了,删了重新写了一遍,将各种注意事宜加上,一次就AC了,看来还是细节方面的问题,觉得自己做题总是会忽略细节,以至于总是不能1A,这是弱点,要改!!!!
代码:
View Code
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> #include <queue> #include <math.h> #define N 50005 using namespace std ; typedef long long ll ; const ll INF = 9999999999 ;//这里的INF要足够大! struct node { int e ; int val ; int next ; }p[2*N]; ll dis[N] , w[N] ;//数组要用long long int vist[N] , n , m , num ; int head[N] ; void init() { memset( vist , 0 , sizeof( vist ) ); for ( int i = 1 ; i <= n ; i++ ) dis[i] = INF ; } void add ( int x , int y , int z ) { p[num].e = y ; p[num].val = z ; p[num].next = head[x] ; head[x] = num++ ; p[num].e = x ; p[num].val = z ; p[num].next = head[y] ; head[y] = num++ ; } void Spfa() { int u , v ; queue<ll>q ; while ( !q.empty()) q.pop(); init(); q.push( 1 ) ; dis[1] = 0 ; while ( !q.empty()) { u = q.front(); q.pop(); vist[u] = 0 ; for ( int i = head[u] ; i != -1 ; i = p[i].next ) { v = p[i].e ; if ( dis[v] > dis[u] + p[i].val ) { dis[v] = dis[u] + p[i].val ; if ( !vist[v] ) { vist[v] = 1 ; q.push ( v ) ; } } } } ll sum =0 ; int flag = 0 ; for ( int i = 1 ; i <= n ; i++ ) { if ( dis[i] == INF ) { flag = 1 ; break ; } sum += dis[i] * w[i] ; } if ( flag )//不要忘了No Answer! printf ( "No Answer\n" ); else printf ( "%I64d\n" , sum ) ; } int main() { int cas , i , x , y , z ; scanf ( "%d" , &cas ); while ( cas-- ) { scanf ( "%d%d" , &n , &m ) ; for ( i = 1 ; i <= n ; i++ ) scanf( "%I64d" , &w[i] ); if ( n == 0 || n == 1 )//注意n==0和n==1的情况 { while ( m-- ) scanf ( "%d%d%d" , &x , &y , &z ) ; printf ( "0\n" ) ; continue ; } memset( head , -1 , sizeof ( head )) ; num = 0 ; for ( i = 1 ; i <= m ; i++ ) { scanf ( "%d%d%d" , &x , &y , &z ); add( x , y , z ) ; } Spfa(); } return 0 ; }