三重算法:
一、 Kosaraju算法
二、 Trajan算法
三、 Gabow算法
前两种马马虎虎刚学会把模板套上去
对应题目:HDU 3072
给你n个点,m条边,每条边有一个权值(传送message代价),已知强连通分支内部不需花费,求minimal cost
步骤:
1.缩点n->scc个点
2.将到这scc个点的最小代价计算出来
3.相加
Trajan模板:
#include<iostream> #include<algorithm> using namespace std; #define min(x,y) x>y?y:x #define maxn 50005 #define max(x,y) x>y?x:y #define INF 10000000 int low[maxn],dfn[maxn],stack[maxn],Belong[maxn]; bool instack[maxn]; int n,stop,scc,step,cost[maxn]; struct Node { int to; int val; struct Node* next; }Edge[maxn],g_Temp[maxn*2]; int g_Pos = 0; void Tarjan(int v) { dfn[v]=low[v] = ++step; instack[v] = true; stack[++stop] = v; Node *temp = Edge[v].next; int t; while(temp!=NULL) { t = temp->to; if(!dfn[t]) { Tarjan(t); low[v] = min(low[v],low[t]); } else if(instack[t] && low[v] > dfn[t]) low[v] = dfn[t]; temp = temp->next; } if(dfn[v] == low[v]) { scc++; do{ t = stack[stop--]; instack[t] = false; Belong[t] = scc; }while(t!=v); } } void solve(int n) { int i; memset(dfn,0,sizeof(dfn)); memset(instack,false,sizeof(instack)); stop = scc = step = 0; for( i = 1; i <= n; i ++) { if(!dfn[i]) { Tarjan(i); } } } void Init() { g_Pos = 0; for(int i = 0 ; i <= n; i ++) { Edge[i].next = NULL; } } void add_edge(int u,int v,int val) { Node *temp = &g_Temp[g_Pos++]; temp->to = v; temp->val = val; temp->next = Edge[u].next; Edge[u].next = temp; } //注意点从1开始标记 int main() { int i,j,m; while(scanf("%d%d",&n,&m)!=EOF) { Init(); int a,b,c; for(i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); add_edge(a+1,b+1,c); } solve(n); for(i=1;i<=scc;i++) cost[i]=INF;//cost[i] record the minimal cost of sending message (from any point) to i for(i=1;i<=n;i++) { Node *temp=Edge[i].next; while(temp!=NULL) { int v=temp->to; int w=temp->val; if(Belong[i]!=Belong[v])//don't belong to one set cost[Belong[v]]=min(cost[Belong[v]],w); temp=temp->next; } } int ans=0; for(i=1;i<=scc;i++) { if(cost[i]==INF)//the vertex whose in-degree=0 -> the root vertex(the only one who know message) continue; ans+=cost[i]; } printf("%d/n",ans); } return 0; }
Kosaraju模板:
(摘自 某大牛 的博客)
#include<stdio.h> #include<string.h> #include<vector> using namespace std; const int N=50010; const int inf=1000000000; int n, m; struct Edge { int v;//next int w;//value }e; vector<Edge> beg[N]; vector<Edge> rebeg[N]; void init() { for(int i=0;i<n;i++) { beg[i].clear(); rebeg[i].clear(); } } void add(int a, int b, int w) { e.v=b; e.w=w; beg[a].push_back(e); e.v = a; rebeg[b].push_back(e); } int order[N]; int id[N],dis[N]; int cnt, scc; void dfs(int u)//先用对原图G进行深搜形成森林(树) { for(int i=0;i<beg[u].size();i++) { int v = beg[u][i].v; if (!id[v]) { id[v]=1; dfs(v); } } order[++cnt]=u; } void redfs(int u) { for(int i=0;i<rebeg[u].size();i++) { int v=rebeg[u][i].v; if(!id[v]) { id[v]=scc; redfs(v); } } } void kosaraju(int n) { cnt=0; memset(order,0,sizeof (order)); //first dfs memset(id,0,sizeof (id)); for(int i=0;i<n;i++) { if(!id[i]) { id[i]=1; dfs(i); } } //second dfs memset(id,0,sizeof (id)); scc=0; for(int i=cnt;i>0;i--) { int u=order[i]; if(!id[u]) { id[u]=++scc; redfs(u); } } } int main() { while(scanf("%d%d",&n,&m)!=EOF) { init(); for(int i=1;i<=m;i++) { int a,b,w; scanf("%d%d%d",&a,&b,&w);//a->b,权值为w add(a,b,w); } kosaraju(n); for (int i=1;i<=scc;i++) dis[i]=inf; for(int u=0;u<n;u++) { for(int j=0;j<beg[u].size();j++) { int v=beg[u][j].v; int w=beg[u][j].w; if(id[u]!=id[v]) dis[id[v]]=min(dis[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; }
3 3 0 1 100 1 2 50 0 2 100 3 3 0 1 100 1 2 50 2 1 100 2 2 0 1 50 0 1 100
150 100 50