hdu1827 强连通

题意:一个人需要联系其他所有人,已知他自己联系每个人的花费,并且他可以联系某个人再让他联系他能联系到的人,给出一系列关系表示 A 能够联系 B。问他最少需要联系多少人,花费多少钱

首先,建成一个有向图,强连通分量内的点可以相互通知,但是如果某个强连通分量入度为0,那么这个强连通分量中的点不能通过其他分量到达,因此只要通知这些入度为0的强连通分量中花费最少的一个人就行了,所以强连通时更新每个分量的最小花费值,然后建边记录入度,联系人数就是入度为0的强连通分量数,而花费就是这些分量的最小花费和。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stack>
 4 #include<queue>
 5 using namespace std;
 6 
 7 const int maxn=1005;
 8 const int maxm=2005;
 9 
10 int head[2][maxn],point[2][maxm],nxt[2][maxm],size[2];
11 int n,t,scccnt;
12 int stx[maxn],low[maxn],scc[maxn],num[maxn],a[maxn],id[maxn],ans1,ans2;
13 stack<int>S;
14 
15 void init(){
16     memset(head,-1,sizeof(head));
17     size[0]=size[1]=0;
18     ans1=ans2=0;
19 }
20 
21 void add(int a,int b,int c=0){
22     point[c][size[c]]=b;
23     nxt[c][size[c]]=head[c][a];
24     head[c][a]=size[c]++;
25     if(c)id[b]++;
26 }
27 
28 void dfs(int s){
29     stx[s]=low[s]=++t;
30     S.push(s);
31     for(int i=head[0][s];~i;i=nxt[0][i]){
32         int j=point[0][i];
33         if(!stx[j]){
34             dfs(j);
35             low[s]=min(low[s],low[j]);
36         }
37         else if(!scc[j]){
38             low[s]=min(low[s],stx[j]);
39         }
40     }
41     if(low[s]==stx[s]){
42         scccnt++;
43         while(1){
44             int u=S.top();S.pop();
45             scc[u]=scccnt;
46             if(a[u]<num[scccnt])num[scccnt]=a[u];
47             if(s==u)break;
48         }
49     }
50 }
51 
52 void setscc(){
53     memset(stx,0,sizeof(stx));
54     memset(scc,0,sizeof(scc));
55     memset(num,0x3f,sizeof(num));
56     memset(id,0,sizeof(id));
57     t=scccnt=0;
58     for(int i=1;i<=n;++i)if(!stx[i])dfs(i);
59     for(int i=1;i<=n;++i){
60         for(int j=head[0][i];~j;j=nxt[0][j]){
61             int k=point[0][j];
62             if(scc[i]!=scc[k]){
63                 add(scc[i],scc[k],1);
64             }
65         }
66     }
67 }
68 
69 int main(){
70     int m;
71     while(scanf("%d%d",&n,&m)!=EOF){
72         init();
73         for(int i=1;i<=n;++i)scanf("%d",&a[i]);
74         while(m--){
75             int a,b;
76             scanf("%d%d",&a,&b);
77             add(a,b);
78         }
79         setscc();
80         for(int i=1;i<=scccnt;++i){
81             if(!id[i]){ans1++;ans2+=num[i];}
82         }
83         printf("%d %d
",ans1,ans2);
84     }
85     return 0;
86 }
View Code
原文地址:https://www.cnblogs.com/cenariusxz/p/4799351.html