题意:一个人需要联系其他所有人,已知他自己联系每个人的花费,并且他可以联系某个人再让他联系他能联系到的人,给出一系列关系表示 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 }