天天看点

SPFA算法之三

//poj 3013 Big Christmas Tree      
#include<iostream>      
#include<deque>      
using namespace std;      
#define maxn 50002      
const __int64 inf=(__int64)1<<63-1;      
struct Edge      
{      
int v;      
int weight;      
int next;      
}Vertex[4*maxn];      
int head[maxn],curr;      
int cases,v,e,i,j,edge[maxn][3],w[maxn];      
void add_edge(int s,int t,int w)        //新增结点不用申请空间, 跑了 579 MS      
{      
Vertex[curr].v=t;      
Vertex[curr].weight=w;      
Vertex[curr].next=head[s];      
head[s]=curr++;      
}      
bool S[maxn];      
__int64 distD[maxn],sum;      
void spfa(int u)      
{      
fill(distD,distD+v+1,inf);      
distD[u]=0;      
memset(S,0,sizeof(S[0])*(v+1));      
S[u]=1;      
deque<int> col;      
col.push_back(u);      
while(!col.empty())      
{      
int uu=col.front();      
col.pop_front();      
S[uu]=0;      
for(i=head[uu];i!=-1;i=Vertex[i].next)      
{      
if(distD[uu]+Vertex[i].weight<distD[Vertex[i].v])      
{      
distD[Vertex[i].v]=distD[uu]+Vertex[i].weight;      
if(!S[Vertex[i].v])      
{      
S[Vertex[i].v]=1;      
col.push_back(Vertex[i].v);      
}      
}      
}      
}      
for(i=1;i<=v;++i)      
if(distD[i]==inf)      
{      
printf("No Answer\n");      
return ;      
}      
sum=0;      
for(i=1;i<=v;++i)      
sum+=w[i]*distD[i];      
printf("%I64d\n",sum);      
}      
int main()      
{      
scanf("%d",&cases);      
while(cases--)      
{      
scanf("%d%d",&v,&e);      
for(i=1;i<=v;++i)      
scanf("%d",&w[i]);      
memset(head,-1,sizeof(head));      
curr=0;      
for(i=1;i<=e;++i)      
{      
scanf("%d%d%d",&edge[i][0],&edge[i][1],&edge[i][2]);      
add_edge(edge[i][0],edge[i][1],edge[i][2]);      
add_edge(edge[i][1],edge[i][0],edge[i][2]);      
}      
spfa(1);      
}      
return 0;      
}      
/*      
这题要有个重要的转化;      
price of an edge will be (sum of weights of all descendant nodes) × (unit price of the edge).      
每条边的代价为该边所有"后继"节点权值(重量weight)之和乘以该边的权值(unit price)。      
换个角度就是每个节点的代价为该节点到根节点的所有边的权值乘以该节点的权值。      
要使得总的花费最小,其实就是求从根结点到每个点的最短路径*该点的权值,然后求和      
数据量很大,采用SPFA算法      
*/