题意:一个有向图,每条边都有花费,问从0节点把消息扩散至每个点所需的最小花费,且一个强连通分量里的节点间传消息不需花费
思路:先缩点成DAG,再求以0为根的最小生成树形图。想一下就知道对每个节点(除了0节点)找一个最近的前驱点即可,因为DAG无环,所以每个节点(除了0节点)这样找下去必然每点的入度均为1,显然最终一定是一个树形图,而且必然是最小生成树
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; int n,m; const int N = 50050; const int M = 100100; struct Edge { int u,v,next,w; }es[M]; int head[N]; int index; int sta[N]; int dfn[N],low[N]; int top; int cnt; int col[N]; int tmp[N]; int scc; int ans[N]; inline void add_edge(int u,int v,int w) { es[++cnt].u=u; es[cnt].v=v; es[cnt].w=w; es[cnt].next=head[u]; head[u]=cnt; } void tarjan(int u) { dfn[u]=low[u]=++index; tmp[u]=1; sta[++top]=u; for(int i=head[u];~i;i=es[i].next) { int v=es[i].v; if(tmp[v]==0) tarjan(v); if(tmp[v]==1) low[u]=min(low[u],low[v]); } if(dfn[u]==low[u]) { ++scc; do { int v=sta[top]; col[v]=scc; tmp[v]=2; }while(sta[top--]!=u); } } void ini() { index=cnt=top=scc=0; memset(head,-1,sizeof(head)); memset(tmp,0,sizeof(tmp)); memset(ans,0x3f,sizeof(ans)); } int main() { while(~scanf("%d%d",&n,&m)) { ini(); for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); v++,u++; add_edge(u,v,w); } for(int i=1;i<=n;i++) if(tmp[i]==0) tarjan(i); for(int i=1;i<=m;i++) { int u=es[i].u,v=es[i].v,w=es[i].w; if(col[u]==col[v]) continue; else { ans[col[v]]=min(ans[col[v]],w); } } ans[col[1]]=0; int ret=0; for(int i=1;i<=scc;i++) ret+=ans[i]; printf("%d\n",ret); } return 0; }