题意,从0点出发,遍历所有点,遍历边时候要付出代价,在一个SCC中的边不要付费。求最小费用。
有向图缩点(无需建立新图,,n《=50000,建则超时),遍历边,若不在一个SCC中,用一个数组更新记录最小到达该连通分量的最小边权即可。。。边聊天,边1A,哈哈。。。
#include<iostream> #include<stack> #include<queue> #include<cstdio> #include<cstring> using namespace std; const int inf=0x3f3f3f3f; const int maxv=50005,maxe=100005; int nume=0;int head[maxv];int e[maxe][3]; void inline adde(int i,int j,int c) { e[nume][0]=j;e[nume][1]=head[i];head[i]=nume; e[nume++][2]=c; } int dfn[maxv];int low[maxv];int vis[maxv];int ins[maxv]; stack<int>sta; int scc[maxv];int numb=0;int times=0; int n,m; void tarjan(int u) { dfn[u]=low[u]=times++; ins[u]=1; sta.push(u); for(int i=head[u];i!=-1;i=e[i][1]) { int v=e[i][0]; if(!vis[v]) { vis[v]=1; tarjan(v); if(low[v]<low[u])low[u]=low[v]; } else if(ins[v]&&dfn[v]<low[u]) { low[u]=dfn[v]; } } if(low[u]==dfn[u]) { numb++; int cur; do { cur=sta.top(); sta.pop(); ins[cur]=0; scc[cur]=numb; }while(cur!=u); } } int mincost_to_v[maxv]; //记录 void solve() { vis[0]=1; tarjan(0); for(int i=0;i<n;i++) for(int j=head[i];j!=-1;j=e[j][1]) { int v=e[j][0]; if(scc[i]!=scc[v]) { if(e[j][2]<mincost_to_v[scc[v]]) { mincost_to_v[scc[v]]=e[j][2]; } } } int sums=0; for(int i=1;i<=numb;i++) { if(mincost_to_v[i]!=inf) //起点 sums+=mincost_to_v[i]; } printf("%d ",sums); } void read_build() { int aa,bb,cc; for(int i=0;i<m;i++) { scanf("%d%d%d",&aa,&bb,&cc); adde(aa,bb,cc); } } void init() { numb=times=nume=0; for(int i=0;i<maxv;i++) { head[i]=-1; ins[i]=dfn[i]=low[i]=scc[i]=vis[i]=0; mincost_to_v[i]=inf; } } int main() { while(~scanf("%d%d",&n,&m)) { init(); read_build(); solve(); } return 0; }