图的联通入门题
BZOJ 1051 [HAOI2006]受欢迎的牛
#include <bits/stdc++.h> const int maxn=5e4+5; struct Edge{ int to, next; }edge[maxn], redge[maxn]; int head[maxn], tot; int rhead[maxn], cnt; int low[maxn], dfn[maxn]; int stk[maxn], instk[maxn], belong[maxn], num[maxn]; int idx, top, scc; int n, m; void addedge(int u, int v) { edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } void tarjan(int u) { int v; low[u]=dfn[u]=++idx; stk[top++]=u, instk[u]=true; for(int i=head[u]; i!=-1; i=edge[i].next) { v=edge[i].to; if(!dfn[v]){ tarjan(v); low[u]=std::min(low[u], low[v]); } else if(instk[v]){ low[u]=std::min(low[u], dfn[v]); } } if(low[u]==dfn[u]) { scc++; do{ v=stk[--top]; instk[v]=false; belong[v]=scc; num[scc]++; }while(v!=u); } } void rebuild() { for(int u=1; u<=n; u++) for(int i=head[u]; i!=-1; i=edge[i].next) { int v=edge[i].to; if(belong[u]!=belong[v]) { redge[cnt].to=belong[v]; redge[cnt].next=rhead[belong[u]]; rhead[belong[u]]=cnt++; } } } int main() { scanf("%d%d", &n, &m); memset(head, -1, sizeof(head)); memset(rhead, -1, sizeof(rhead)); for(int i=0; i<m; i++) { int u, v; scanf("%d%d", &u, &v); addedge(u, v); } for(int u=1; u<=n; u++) if(!dfn[u]) tarjan(u); rebuild(); int ok=0, ans; for(int u=1; u<=scc; u++) if(rhead[u]==-1){ ok++; ans=num[u]; } printf("%d", ok==1? ans:0); return 0; }
仅记录缩点重构图的出度
1 #include <bits/stdc++.h> 2 3 const int maxn=5e4+5; 4 5 struct Edge{ 6 int to, next; 7 }edge[maxn], redge[maxn]; 8 int head[maxn], tot; 9 int out[maxn]; 10 11 int low[maxn], dfn[maxn]; 12 int stk[maxn], instk[maxn], belong[maxn], num[maxn]; 13 int idx, top, scc; 14 int n, m; 15 16 void addedge(int u, int v) 17 { 18 edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; 19 } 20 21 void tarjan(int u) 22 { 23 int v; 24 low[u]=dfn[u]=++idx; 25 stk[top++]=u, instk[u]=true; 26 for(int i=head[u]; i!=-1; i=edge[i].next) 27 { 28 v=edge[i].to; 29 if(!dfn[v]){ 30 tarjan(v); 31 low[u]=std::min(low[u], low[v]); 32 } 33 else if(instk[v]){ 34 low[u]=std::min(low[u], dfn[v]); 35 } 36 } 37 if(low[u]==dfn[u]) 38 { 39 scc++; 40 do{ 41 v=stk[--top]; 42 instk[v]=false; 43 belong[v]=scc; 44 num[scc]++; 45 }while(v!=u); 46 } 47 } 48 49 void rebuild() 50 { 51 for(int u=1; u<=n; u++) 52 for(int i=head[u]; i!=-1; i=edge[i].next) 53 { 54 int v=edge[i].to; 55 if(belong[u]!=belong[v]) 56 out[belong[u]]=1; 57 } 58 } 59 60 int main() 61 { 62 scanf("%d%d", &n, &m); 63 memset(head, -1, sizeof(head)); 64 for(int i=0; i<m; i++) 65 { 66 int u, v; scanf("%d%d", &u, &v); 67 addedge(u, v); 68 } 69 for(int u=1; u<=n; u++) 70 if(!dfn[u]) tarjan(u); 71 rebuild(); 72 int ok=0, ans; 73 for(int u=1; u<=scc; u++) 74 if(!out[u]){ 75 ok++; ans=num[u]; 76 } 77 printf("%d", ok==1? ans:0); 78 return 0; 79 }
BZOJ 1529 Ska Piggy Panks https://www.luogu.org/problem/P3420
题意:Byteazar 有 N 个小猪存钱罐. 每个存钱罐只能用钥匙打开或者砸开. Byteazar 已经把每个存钱罐的钥匙放到了某些存钱罐里,他想尽量少的打破存钱罐取出所有的钱,问最少要打破多少个存钱罐。给出:表示第i个存钱罐对应的钥匙放置在了第x个存钱罐中。
题解:1.tarjan缩点重构后求入度为0的点的个数,此题中会爆内存。
2.并查集直接搞就行。
#include <bits/stdc++.h> const int maxn=1e6+5; int fa[maxn]; int find(int x) { return fa[x]==x? x:fa[x]=find(fa[x]); } int main() { int n; scanf("%d", &n); for(int i=1; i<=n; i++) fa[i]=i; for(int i=1; i<=n; i++) { int x; scanf("%d", &x); int p=find(x), q=find(i); if(p!=q) fa[q]=p; } int ans=0; for(int i=1; i<=n; i++) if(fa[i]==i) ans++; printf("%d\n", ans); return 0; }
CF 427C Checkposts http://codeforces.com/problemset/problem/427/C
题意:条件:A checkpost at junction i can protect junction j if either i = j or the police patrol car can go to j from i and then come back to i. Building checkposts costs some money
求:You have to determine the minimum possible money needed to ensure the security of all the junctions. Also you have to find the number of ways to ensure the security in minimum price and in addition in minimum number of checkposts.
题解:tarjan的时候维护num【】,minw【】即可。ans1连加,ans2连乘
#include <bits/stdc++.h> const int maxn=3e5+5, mod=1e9+7; struct Edge{ int to, next; }edge[maxn]; int head[maxn], tot; int low[maxn], dfn[maxn]; int stk[maxn], instk[maxn], num[maxn]; int idx, top, scc; int n, m; int w[maxn], minw[maxn]; void addedge(int u, int v) { edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } void tarjan(int u) { int v; low[u]=dfn[u]=++idx; stk[top++]=u, instk[u]=true; for(int i=head[u]; i!=-1; i=edge[i].next) { v=edge[i].to; if(!dfn[v]){ tarjan(v); low[u]=std::min(low[u], low[v]); } else if(instk[v]){ low[u]=std::min(low[u], dfn[v]); } } if(low[u]==dfn[u]) { scc++; do{ v=stk[--top]; instk[v]=false; if(minw[scc]>w[v]){ num[scc]=1; minw[scc]=w[v]; } else if(minw[scc]==w[v]) num[scc]++; }while(v!=u); } } int main() { memset(head, -1, sizeof(head)); memset(minw, 0x3f, sizeof(minw)); scanf("%d", &n); for(int i=1; i<=n; i++) scanf("%d", &w[i]); scanf("%d", &m); for(int i=0; i<m; i++) { int u, v; scanf("%d%d", &u, &v); addedge(u, v); } for(int u=1; u<=n; u++) if(!dfn[u]) tarjan(u); long long ans1=0, ans2=1; for(int i=1; i<=scc; i++) { ans1+=minw[i]; ans2=(ans2*num[i])%mod; } printf("%lld %lld\n", ans1, ans2); return 0; }