概念
最高强连通分量:设si是有向图G中的一个强连通分量,如果该强连通分量与图G中其它强连通分量的所有弧都是向外延伸的,即该强连通分量入度为0,出度不为0,称之为最高强连通分量。
点基:在有向图 G=(V,E) 中,设B是V的子集,对于任意点y属于V,但不属于B,B中都存在一个点x是y的前代(即存在一条 x->y 的边),则称B是V的一个点基。
最小点基:顶点最少的点基。
最小权点基:顶点对应的权值之和最小的点基。
算法
求最小点基:1、找出图G中的所以的强连通分量。
2、从强连通分量中找出所有的最高强连通分量,也就是缩点后入度为0的点。
3、从每个最高强连通分量随便取一个点,这些点组成的点集就是一个最小点基。
求最小权点基:1、找出图G中的所以的强连通分量。
2、从强连通分量中找出所有的最高强连通分量,也就是缩点后入度为0的点。
3、从每个最高强连通分量取一个权值最小的点,这些点组成的点集就是一个最小权点基。
例题
就是裸的求最小点基和最小权点基
1 //#include<bits/stdc++.h> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 #include<string> 7 #include<vector> 8 #include<stack> 9 #include<bitset> 10 #include<cstdlib> 11 #include<cmath> 12 #include<set> 13 #include<list> 14 #include<deque> 15 #include<map> 16 #include<queue> 17 #define ll long long 18 #define MOD 1000000007 19 #define INF 0x3f3f3f3f 20 #define mem(a,x) memset(a,x,sizeof(a)) 21 #define lowbit(x) x&(-x) 22 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 23 using namespace std; 24 25 int dfn[2005]; 26 int low[2005]; 27 int vis[2005]; 28 int stacks[2005]; 29 int color[2005]; 30 int cnt[2005]; 31 int deep,sum,top; 32 int n,m; 33 vector<int>g[2005]; 34 void tarjan(int u) 35 { 36 dfn[u]=++deep; 37 low[u]=deep; 38 vis[u]=1; 39 stacks[++top]=u; 40 for(int i=0;i<g[u].size();i++){ 41 int v=g[u][i]; 42 if(!dfn[v]) 43 { 44 tarjan(v); 45 low[u]=min(low[u],low[v]); 46 }else{ 47 if(vis[v]){ 48 low[u]=min(low[v],low[u]); 49 } 50 } 51 } 52 if(dfn[u]==low[u]) 53 { 54 color[u]=++sum; 55 vis[u]=0; 56 while(stacks[top]!=u) 57 { 58 color[stacks[top]]=sum; 59 vis[stacks[top--]]=0; 60 } 61 top--; 62 } 63 } 64 int val[2005]; 65 int in[2005],out[2005]; 66 int main() 67 { 68 while(~scanf("%d %d",&n,&m)){ 69 deep=0;top=0;sum=0; 70 for(int i=1;i<=n;i++){ 71 dfn[i]=0;vis[i]=0;low[i]=0;cnt[i]=0; 72 in[i]=0;out[i]=0; 73 g[i].clear(); 74 } 75 for(int i=1;i<=n;i++){ 76 scanf("%d",&val[i]); 77 } 78 for(int i=1;i<=m;i++){ 79 int from,to; 80 scanf("%d %d",&from,&to); 81 g[from].push_back(to); 82 } 83 for(int i=1;i<=n;i++){ 84 if(!dfn[i]){ 85 tarjan(i); 86 } 87 } 88 for(int i=1;i<=n;i++){ 89 for(auto v:g[i]){ 90 if(color[i]!=color[v]){ 91 out[color[i]]++; 92 in[color[v]]++; 93 } 94 } 95 } 96 ll num=0,ans=0; 97 for(int i=1;i<=sum;i++){ 98 ll minn=INF; 99 if(in[i]==0){ 100 num++; 101 for(int j=1;j<=n;j++){ 102 if(color[j]==i){ 103 minn=min(minn,1ll*val[j]); 104 } 105 } 106 ans+=minn; 107 } 108 } 109 printf("%lld %lld ",num,ans); 110 } 111 return 0; 112 }