soj 2832 强连通分量

来源:互联网 发布:哪个软件看韩剧最全 编辑:程序博客网 时间:2024/06/10 22:56

 

第一次做出来,第二次居然没做出来。。。

#include<stdio.h>#include<stdlib.h>#include<math.h>#include<iostream>#include<string.h>#include<algorithm>#include<queue>#include<vector>#define maxn 5010#define INF 99999999using namespace std;int cost[maxn];vector<int> edge[maxn]; //用向量建立邻接表 int dfn[maxn];//搜索到的次序编号 int low[maxn];//能追溯到最早的栈中节点的次序 bool vis[maxn];//是否访问过 int sstack[maxn];//放节点的栈 bool instack[maxn];//是否在栈中 int scc[maxn];//强连通分量 int idex,cnt,top;//强连通个数int n,m; void tarjan(int u){vis[u]=1;dfn[u]=low[u]=++idex;sstack[++top]=u;instack[u]=1;for(int i=0;i<edge[u].size();i++){int v=edge[u][i];if(!vis[v]){tarjan(v);low[u]=min(low[u],low[v]);}else if(instack[v]){low[u]=min(low[u],dfn[v]);}}if(dfn[u]==low[u]) //u为子树的根 {int t=0;cnt++;while(u!=t){t=sstack[top--];instack[t]=0;scc[t]=cnt;}}}void solve(){memset(vis,0,sizeof(vis));idex=top=cnt=0;for(int i=1;i<=n;i++){if(!vis[i])tarjan(i);}} int main(){int id,cst;int a,b;int cost[maxn],cc[maxn],ind[maxn];while(scanf("%d%d",&n,&m)==2){int i,j;for(i=1;i<=n;i++){scanf("%d%d",&id,&cst);cost[id]=cst;}for(i=1;i<=n;i++)edge[i].clear();for(i=0;i<m;i++) //建立邻接表 {scanf("%d%d",&a,&b);edge[a].push_back(b);}solve();for(i=0;i<=n;i++) //这里不能用memsetcc[i]=INF;memset(ind,0,sizeof(ind));for(i=1;i<=n;i++) //缩点取最小代价 {cc[scc[i]]=min(cc[scc[i]],cost[i]);}for(i=1;i<=n;i++) //统计入度 {for(j=0;j<edge[i].size();j++){int v=edge[i][j];if(scc[i]!=scc[v])ind[scc[v]]++;}}int ans=0;for(i=1;i<=cnt;i++) //入度为0,建警察局 {if(ind[i]==0)ans+=cc[i];}printf("%d\n",ans);} return 0;}


 

原创粉丝点击