即:有向图中的最小生成树(外向树)
1.对每个点求出边权最小的入边,并记录
2.看1,中组成的图有无环,且能否组成树
3.若存在环,则将环缩成一个点,重新赋边权,回到1.
(洛谷模板)
#include<bits/stdc++.h> using namespace std; #define re register #define ll long long #define get getchar() #define in inline in int read() { int t=0; char ch=get; while(ch<'0' || ch>'9') ch=get; while(ch<='9' && ch>='0') t=t*10+ch-'0', ch=get; return t; } const int _=1e4+23; const int inf=0x3f3f3f3f; int rt, n, m; struct E{ int u, v, w; }ed[_]; int id[_], mn[_], pre[_], vis[_]; ll ans=0; in void zhuliu(int n) { while(1) { int cnt=0; for(re int i=1;i<=n;++i) mn[i]=inf; for(re int i=1;i<=m;++i) //找到最小入边 if(ed[i].w<mn[ed[i].v] && ed[i].u!=ed[i].v) mn[ed[i].v]=ed[i].w, pre[ed[i].v]=ed[i].u; for(re int i=1;i<=n;++i) if(i!=rt && mn[i]==inf) {ans=-1;return ;} //判断是否能组成外向树 for(re int i=1;i<=n;++i) vis[i]=id[i]=0; for(re int i=1;i<=n;++i) { if(i==rt) continue; ans+=mn[i]; int v=i; while(vis[v]!=i && !id[v] && v!=rt) vis[v]=i, v=pre[v]; //找环 if(!id[v] && v!=rt) //把环缩点 { id[v]=++cnt; for(re int u=pre[v];u!=v;u=pre[u]) id[u]=cnt; } } if(cnt==0) break; for(re int i=1;i<=n;++i) if(!id[i]) id[i]=++cnt; for(re int i=1;i<=m;++i) //重新赋边权与标号 { int u=ed[i].u, v=ed[i].v; ed[i].u=id[u], ed[i].v=id[v]; if(ed[i].u!=ed[i].v) ed[i].w-=mn[v]; } rt=id[rt], n=cnt; } return ; } int main() { n=read(), m=read(), rt=read(); for(re int i=1;i<=m;++i) ed[i].u=read(), ed[i].v=read(), ed[i].w=read(); zhuliu(n); printf("%lld\n", ans); return 0; }