题意:人和人之间传递消息,然后一些人到人的传递需要代价,如果一个人可以和另一个人直接或者间接的相互传递,那么他们之间的传递代价忽略不计,问说有人都知道消息的最小代价?
想法:显然tarjan缩点,然后用最小树形图求解,或者小贪心一下,因为最小树形图只跑了一层,显然每一个团体都是从另一个团体得到消息,又因为只有一个入度为0缩点(Believe kzc_tc’s working! There always is a way for him to communicate with all other intelligence personnel.),那么只要得到可以传送到这个团体的所有代价中取出最小的即可。
#include<iostream> #include<cstring> #include<stack> #include<cstdio> #define INF 0x7ffffff #define mm(x) memset(x,0,sizeof(x)) using namespace std; const int N=50000+9; const int M=100000+9; stack<int>s; struct node { int to,next; int w; }G[M]; struct edge { int u,v,w; }NG[M]; int indegree[N]; int instack[N],paint[N],col,index,dfn[N],low[N]; int head[N],cnt,Ncnt; class tarjan { public: int MIN(int a,int b) { if(a<b) return a; return b; } void Init() { while(!s.empty()) s.pop(); mm(instack); mm(paint); mm(dfn); mm(low); mm(indegree); index=1; col=0; memset(head,-1,sizeof(head)); cnt=0; Ncnt=0; } void add(int a,int b,int c) { G[cnt].to=b; G[cnt].w=c; G[cnt].next=head[a]; head[a]=cnt++; } void Nadd(int a,int b,int c) { NG[Ncnt].u=a; NG[Ncnt].v=b; NG[Ncnt++].w=c; } void Tarjan(int u) { dfn[u]=low[u]=index++; instack[u]=1; s.push(u); for(int i=head[u];i+1;i=G[i].next) { int v=G[i].to; if(!dfn[v]) { Tarjan(v); low[u]=MIN(low[u],low[v]); } else if(instack[v]) { low[u]=MIN(low[u],dfn[v]); } } if(low[u]==dfn[u]) { int k=s.top(); while(k!=u) { s.pop(); paint[k]=col; instack[k]=0; k=s.top(); } s.pop(); paint[u]=col; instack[u]=0; col++; } } void build_NG(int n) { for(int i=0;i<n;i++) { for(int j=head[i];j+1;j=G[j].next) { int u=i,v=G[j].to; if(paint[u]!=paint[v]) { Nadd(paint[u],paint[v],G[j].w); } } } } }pre_deal; __int64 directed_mst(int root,int nv,int ne) { __int64 res=0; int in[N],pre[N]; int id[N],vis[N]; while(true) { //==找最小入边== for(int i=0;i<nv;i++) { in[i]=INF; } for(int i=0;i<ne;i++) { int u=NG[i].u; int v=NG[i].v; if(NG[i].w<in[v]&&u!=v) { pre[v]=u; in[v]=NG[i].w; } } for(int i=0;i<nv;i++) { if(i==root) continue; if(in[i]==INF) return -1; } //==找有向圈== int cntnode=0; in[root]=0; memset(id,-1,sizeof(id)); memset(vis,-1,sizeof(vis)); for(int i=0;i<nv;i++) { int v=i; res+=in[i]; while(vis[v]!=i&&id[v]==-1&&v!=root) { vis[v]=i; v=pre[v]; } if(id[v]==-1&&v!=root) { for(int u=pre[v];u!=v;u=pre[u]) { id[u]=cntnode; } id[v]=cntnode++; } } if(cntnode==0) break; for(int i=0;i<nv;i++) { if(id[i]==-1) { id[i]=cntnode++; } } //==缩点,重新标记== for(int i=0;i<ne;i++) { int v=NG[i].v; NG[i].u=id[NG[i].u]; NG[i].v=id[NG[i].v]; if(NG[i].u!=NG[i].v) { NG[i].w-=in[v]; } } nv=cntnode; root=id[root]; } return res; } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { int root; pre_deal.Init(); while(m--) { int a,b,c; scanf("%d%d%d",&a,&b,&c); indegree[b]++; pre_deal.add(a,b,c); } for(int i=0;i<n;i++) { if(!dfn[i]) pre_deal.Tarjan(i); } int nv=col--; pre_deal.build_NG(n); /*cout<<"col="<<col<<endl; cout<<"Ncnt="<<Ncnt<<endl; cout<<"------NG------"<<endl; for(int i=0;i<Ncnt;i++) { cout<<NG[i].u<<"-->"<<NG[i].v<<"的价值"<<NG[i].w<<endl; } cout<<"根是:"<<paint[0]<<endl;*/ for(int i=0;i<n;i++) { if(indegree[i]==0) { root=i; break; } } __int64 ans=directed_mst(paint[root],nv,Ncnt); printf("%I64d\n",ans); } return 0; }