USACO 5.3 Network of Schools (强连通分量,缩点)
2015-03-31 23:31:55
思路:给出一个有向图,让你求最少给多少个点(学校)发软件,能使得软件传到全部点(学校)。
另外还有第二问:添加最少的边使得给任意一点(学校)发软件,能传到全部点(学校)。
一开始是想直接并查集乱搞... 后来明白题意后... 首先强连通分量里面的点是互相可达的,所以先tarjan一遍再缩点。
接着考虑第一问,显然是找出缩点后所有入度为0的点,其数量便是第一个答案。
然后考虑第二问,这个问题以前hdu2767一样,添加最少边使得整个图强连通,那么答案就是缩点后:max(入度为0的点数,出度为0的点数)
1 /* 2 ID:naturec1 3 PROG: schlnet 4 LANG: C++ 5 */ 6 #include <cstdio> 7 #include <cstring> 8 #include <cstdlib> 9 #include <cmath> 10 #include <vector> 11 #include <map> 12 #include <set> 13 #include <stack> 14 #include <queue> 15 #include <string> 16 #include <iostream> 17 #include <algorithm> 18 using namespace std; 19 20 #define MEM(a,b) memset(a,b,sizeof(a)) 21 #define REP(i,n) for(int i=0;i<(n);++i) 22 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 23 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 24 #define MP(a,b) make_pair(a,b) 25 26 typedef long long ll; 27 typedef pair<int,int> pii; 28 const int INF = (1 << 30) - 1; 29 const int MAXN = 110; 30 31 int N,tot,scnt; 32 int first[MAXN],ecnt; 33 int dfn[MAXN],low[MAXN],sc[MAXN]; 34 int din[MAXN],dout[MAXN]; 35 stack<int> stk; 36 37 struct edge{ 38 int v,next; 39 }e[MAXN * MAXN]; 40 41 void Init(){ 42 MEM(first,-1); 43 ecnt = 0; 44 tot = 0; 45 scnt = 0; 46 } 47 48 void Add_edge(int u,int v){ 49 e[++ecnt].next = first[u]; 50 e[ecnt].v = v; 51 first[u] = ecnt; 52 } 53 54 void Dfs(int p){ 55 dfn[p] = low[p] = ++tot; 56 stk.push(p); 57 for(int i = first[p]; ~i; i = e[i].next){ 58 int v = e[i].v; 59 if(!dfn[v]){ 60 Dfs(v); 61 low[p] = min(low[p],low[v]); 62 } 63 else if(!sc[v]){ 64 low[p] = min(low[p],dfn[v]); 65 } 66 } 67 if(dfn[p] == low[p]){ 68 scnt++; 69 for(;;){ 70 int x = stk.top(); stk.pop(); 71 sc[x] = scnt; 72 if(x == p) break; 73 } 74 } 75 } 76 77 void Tarjan(){ 78 MEM(low,0); 79 MEM(dfn,0); 80 MEM(sc,0); 81 while(!stk.empty()) stk.pop(); 82 FOR(i,1,N){ 83 if(!dfn[i]) Dfs(i); 84 } 85 } 86 87 int main(){ 88 freopen("schlnet.in","r",stdin); 89 freopen("schlnet.out","w",stdout); 90 int a; 91 Init(); 92 scanf("%d",&N); 93 FOR(i,1,N){ 94 while(scanf("%d",&a) != EOF && a){ 95 Add_edge(i,a); 96 } 97 } 98 Tarjan(); 99 FOR(i,1,N){ 100 for(int j = first[i]; ~j; j = e[j].next){ 101 int v = e[j].v; 102 if(sc[i] != sc[v]){ 103 dout[sc[i]]++; 104 din[sc[v]]++; 105 } 106 } 107 } 108 int cnt1 = 0,cnt2 = 0; 109 FOR(i,1,scnt) if(din[i] == 0) cnt1++; 110 FOR(i,1,scnt) if(dout[i] == 0) cnt2++; 111 int ans1 = cnt1 == 0 ? 1 : cnt1; 112 int ans2 = scnt == 1 ? 0 : max(cnt1,cnt2); 113 printf("%d\n%d\n",ans1,ans2); 114 return 0; 115 }