题意:一个人需要联系其他所有人,已知他自己联系每个人的花费,并且他可以联系某个人再让他联系他能联系到的人,给出一系列关系表示 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\n",ans1,ans2); 84 } 85 return 0; 86 }
时间: 2024-10-10 13:33:15