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\n",ans1,ans2);
84     }
85     return 0;
86 }

时间: 2024-10-10 13:33:15

hdu1827 强连通的相关文章

强连通缩点— HDU1827

强连通缩点以后最终形成的是一棵树 我们可以根据树的性质来看缩点以后的强连通分量图,就很好理解了 /* gyt Live up to every day */ #include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<stack> #include<cstring> #include<

HDU1827 Summer Holiday(强连通+缩点+最小传递费用)

题意:给出人物关系图,要把一个通知告诉所有人,告诉每一个人有一个费用,现在想知道最小通知的人与费用. 思路:利用Tarjan算法,对原图进行缩点,然后找出入度为0 的点,那么这个人是必须要通知的,由于经过缩点,所以,如果这个点是缩点来的,那就枚举下这个点里的任一个点,找到最小的费用点. #include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<set

HDU-1827 Summer Holiday

To see a World in a Grain of Sand And a Heaven in a Wild Flower, Hold Infinity in the palm of your hand And Eternity in an hour. -- William Blake 听说lcy帮大家预定了新马泰7日游,Wiskey真是高兴的夜不能寐啊,他想着得快点把这消息告诉大家,虽然他手上有所有人的联系方式,但是一个一个联系过去实在太耗时间和电话费了.他知道其他人也有一些别人的联系方式

Kosaraju算法解析: 求解图的强连通分量

1. 定义 连通分量:在无向图中,即为连通子图. 上图中,总共有四个连通分量.顶点A.B.C.D构成了一个连通分量,顶点E构成了一个连通分量,顶点F,G和H,I分别构成了两个连通分量. 强连通分量:有向图中,尽可能多的若干顶点组成的子图中,这些顶点都是相互可到达的,则这些顶点成为一个强连通分量. 上图中有三个强连通分量,分别是a.b.e以及f.g和c.d.h. 2. 连通分量的求解方法 对于一个无向图的连通分量,从连通分量的任意一个顶点开始,进行一次DFS,一定能遍历这个连通分量的所有顶点.所以

POJ 2186 Popular Cows 强连通分量模板

题意 强连通分量,找独立的块 强连通分量裸题 #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <algorithm> #include <iostream> using namespace std; const int maxn = 50005; int n, m; struct Edge { int v, next;

USACO network of school 强连通分量

这个题的意思是有一个有向图, 每个顶点可以发送软件到与其相连的顶点上, 现在问1,至少发送给几个顶点能满足所有顶点都收到软件, 2:如果想让这个图变成强连通图,至少添几条边.  特例是给定的图是一个强连通图的话答案是1, 0. 一般情况下我们先将这个图的强连通分量求出来缩成一个点然后统计入度为0的点和出度为0的点的个数, 答案一就是入度为0的点的个数, 答案就是他们两个之间的最大值.代码如下: /* ID: m1500293 LANG: C++ PROG: schlnet */ #include

hdu3861 强连通+最小路径覆盖

题意:有 n 个点,m 条边的有向图,需要将这些点分成多个块,要求:如果两点之间有路径能够互相到达,那么这两个点必须分在同一块:在同一块内的任意两点相互之间至少要有一条路径到达,即 u 到达 v 或 v 到达 u:每个点都只能存在于单独一个块内.问最少需要划分多少块. 首先,对于如果两点之间能够相互到达则必须在同一块,其实也就是在同一个强连通分量中的点必须在同一块中,所以首先就是强连通缩点.然后在同一块内的任意两点之间要有一条路,那么其实就是对于一块内的强连通分量,至少要有一条路径贯穿所有分量.

HDU 3072 Intelligence System (强连通分量)

题目地址:HDU 3072 这题一开始理解错题目意思了..(不得不吐槽一下题目意思确实不好理解..)用的强连通+最小生成树做的...然后错了好多遍...sad..题目意思是从一个给定点向其他所有点通信的最少花费,那么入度为0的点肯定是那个给定点.然后对于其它点,枚举就好了.找一个到他花费最少的点的花费. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue&g

强连通分量(学习心得)

定义:有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量. 求强连通分量: vector<int>pic[maxn]; int dfn[maxn],low[maxn],ans[maxn]; bool ins[maxn]; stack<int>st; int dind=0,block=