Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 901 Accepted Submission(s): 401
题意:给你n个点,m条边,每条边有一个权值(传送message代价),已知强连通分支内部不需花费,求minimal cost
步骤:
1.缩点n->scc个点
2.将到这scc个点的最小代价计算出来
3.相加
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int VM=50010; const int EM=100010; const int INF=0x3f3f3f3f; struct Edge{ int to,nxt; int cap; }edge[EM<<1]; int n,m,cnt,head[VM],cost[VM]; int dep,top,atype; int dfn[VM],low[VM],vis[VM],stack[VM],belong[VM]; void addedge(int cu,int cv,int cw){ edge[cnt].to=cv; edge[cnt].cap=cw; edge[cnt].nxt=head[cu]; head[cu]=cnt++; } void Tarjan(int u){ dfn[u]=low[u]=++dep; stack[top++]=u; vis[u]=1; for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(!dfn[v]){ Tarjan(v); low[u]=min(low[u],low[v]); }else if(vis[v]){ low[u]=min(low[u],dfn[v]); } } int j; if(dfn[u]==low[u]){ atype++; do{ j=stack[--top]; belong[j]=atype; vis[j]=0; }while(u!=j); } } void init(){ cnt=0; memset(head,-1,sizeof(head)); dep=0, top=0, atype=0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(vis,0,sizeof(vis)); memset(belong,0,sizeof(belong)); } int main(){ //freopen("input.txt","r",stdin); while(~scanf("%d%d",&n,&m)){ init(); int u,v,w; while(m--){ scanf("%d%d%d",&u,&v,&w); u++;v++; addedge(u,v,w); } for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i); memset(cost, INF, sizeof(cost)); int ans=0; for(int u=1;u<=n;u++) for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(belong[u]!=belong[v]){ cost[belong[v]]=min(cost[belong[v]],edge[i].cap); } } for(int i=1;i<=atype;i++){ if(cost[i]!=INF) ans+=cost[i]; //printf("---------- i = %d %d\n",i,cost[i]); } /*换成下面这样也对, for(int i=1;i<atype;i++) ans+=cost[i]; */ printf("%d\n",ans); } return 0; }
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int INF=0x3f3f3f3f; const int VM=50010; const int EM=100010; struct Edge{ int to,nxt; int cap; }edge1[EM],edge2[EM]; //edge1是正向图G edge2 是图G的逆GT int head1[VM],head2[VM],n,cnt; void addedge(int cu,int cv,int cw){ edge1[cnt].to=cv; edge1[cnt].cap=cw; edge1[cnt].nxt=head1[cu]; head1[cu]=cnt; edge2[cnt].to=cu; edge2[cnt].cap=cw; edge2[cnt].nxt=head2[cv]; head2[cv]=cnt++; } int k,scc; int order[VM],vis[VM],scc_id[VM],dis[VM]; //order是记录点出栈的时间,ssc_id 记强连通分量的集合 在同一强连通分量中 ssc_id[i] 的值相同 int DFS(int u){ //搜索图G 记录各点出栈时间 for(int i=head1[u];i!=-1;i=edge1[i].nxt){ int v=edge1[i].to; if(!vis[v]){ vis[v]=1; DFS(v); } } order[++k]=u; //order [1..n] 记录的是出栈时间最早的 order[1]最早 return 0; } int reDFS(int u){ //搜索GT图 缩点 for(int i=head2[u];i!=-1;i=edge2[i].nxt){ int v=edge2[i].to; if(scc_id[v]==0){ scc_id[v]=scc; reDFS(v); } } return 0; } int Kosaraju(){ int i,u; k=scc=0; //scc是强连通图的个数 memset(order,0,sizeof(order)); memset(vis,0,sizeof(vis)); for(i=0;i<n;i++) if(!vis[i]){ vis[i]=1; DFS(i); } memset(scc_id,0,sizeof(scc_id)); for(i=n;i>0;i--){ //从出栈时间最晚的开始搜索缩点 这样不会连通到别的树上 u=order[i]; if(scc_id[u]==0){ scc_id[u]=++scc; reDFS(u); } } return scc; } int main(){ //freopen("input.txt","r",stdin); int m; while(~scanf("%d%d",&n,&m)){ cnt=0; memset(head1,-1,sizeof(head1)); memset(head2,-1,sizeof(head2)); int u,v,w; for(int i=0;i<m;i++){ scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); } Kosaraju(); memset(dis,0x3f,sizeof(dis)); for(u=0;u<n;u++) for(int i=head1[u];i!=-1;i=edge1[i].nxt){ v=edge1[i].to; w=edge1[i].cap; if(scc_id[u]!=scc_id[v]) dis[scc_id[v]]=dis[scc_id[v]]<w?dis[scc_id[v]]:w; } int ans=0; for(int i=1;i<=scc;i++){ if(dis[i]==INF) dis[i]=0; ans+=dis[i]; } printf("%d\n",ans); } return 0; }