Good question. For an undirected graph, find the minimum number of vertices that are black, and delete any vertex. Each vertex is connected to at least one black dot.
I did not know how to do it at the beginning. Read the White Book. For a Unicom component, if it has two or more cut points, then any point in the middle of the component does not need to be colored. If this Unicom component happens to have a cut point, the component needs to be colored on any of the non-cut points. If the component does not have a cut point, take any two dyes.
It is not difficult to understand, because at most one vertex can be deleted. Therefore, if the deleted vertex is not a cut point, the component is absolutely connected. At the same time, you can use the cut point to connect the component outside, if you delete a cut point, it is not connected to the inside, so at least one black spot is required. If there are two cut points, obviously, no matter which point you remove, this component is connected to the outside.
With this idea, the question is simple.
Summon code:
Solution 1: Find all connected components, determine the number of cut points for each connected component, and update the answer.
#include <iostream>#include <cstdio>#include <cstring>#include <vector>#define maxn 201000typedef long long ll;using namespace std;int first[maxn],next[maxn],to[maxn],edge;//graphvector<int> bcc[maxn];int N,bccnum;//the bcc dataint iscut[maxn],belong[maxn],d[maxn],low[maxn],child;int U[maxn],V[maxn],stack[maxn],top;//stackint n,m,cas=0,T;ll ans,tot;void _init(){ ans=1,tot=0,edge=-1,child=bccnum=0,top=0; for (int i=1; i<=n; i++) first[i]=-1,d[i]=low[i]=iscut[i]=belong[i]=0;}void addedge(int uu,int vv){ edge++; to[edge]=vv,next[edge]=first[uu],first[uu]=edge; edge++; to[edge]=uu,next[edge]=first[vv],first[vv]=edge;}void dfs(int cur,int fa){ d[cur]=low[cur]=d[fa]+1; for (int i=first[cur]; i!=-1; i=next[i]) { if (to[i]==fa) continue; if (!d[to[i]]) { if (fa==0) child++; top++; U[top]=cur,V[top]=to[i]; dfs(to[i],cur); low[cur]=min(low[cur],low[to[i]]); if (low[to[i]]>=d[cur]) { iscut[cur]=1; bccnum++,bcc[bccnum].clear(); for (;;top--) { if (belong[U[top]]!=bccnum) belong[U[top]]=bccnum,bcc[bccnum].push_back(U[top]); if (belong[V[top]]!=bccnum) belong[V[top]]=bccnum,bcc[bccnum].push_back(V[top]); if (U[top]==cur && V[top]==to[i]) { top--; break; } } } } else low[cur]=min(low[cur],d[to[i]]); } if (fa==0 && child==1) iscut[cur]=0;}int main(){ while (scanf("%d",&m) && (m)) { n=-1; for (int i=1; i<=m; i++) { scanf("%d%d",&U[i],&V[i]); n=max(n,max(U[i],V[i])); } _init(); for (int i=1; i<=m; i++) addedge(U[i],V[i]); for (int i=1; i<=n; i++) if (!d[i]) { if (first[i]==-1) { tot++; continue; } child=0; dfs(i,0); } for (int i=1; i<=bccnum; i++) { int cutnum=0; for (unsigned j=0; j<bcc[i].size(); j++) if (iscut[bcc[i][j]]) cutnum++; if (cutnum==1) { tot++; ans*=bcc[i].size()-1; } else if (cutnum==0) { tot+=2; ll tmp=bcc[i].size(); ans*=tmp*(tmp-1)/2; } } printf("Case %d: %lld %lld\n",++cas,tot,ans); } return 0;
Solution 2: mark all the cut points, starting from the non-cut point each time, to see how many non-cut points can be reached, and the total number of cut points adjacent, (In fact, it traverses the UNICOM component, but the implementation is simpler ).
#include <iostream>#include <cstdio>#include <cstring>#define maxn 200200typedef long long ll;using namespace std;int first[maxn],to[maxn],next[maxn],edge;int U[maxn],V[maxn];int d[maxn],low[maxn],tag[maxn];bool iscut[maxn],vis[maxn];int n,m,tot,child,sum,cut;ll ans;void _init(){ tot=0,ans=1,edge=-1; for (int i=1; i<=n; i++) first[i]=-1,iscut[i]=vis[i]=false,tag[i]=low[i]=d[i]=0;}void addedge(int uu,int vv){ edge++; to[edge]=vv,next[edge]=first[uu],first[uu]=edge; edge++; to[edge]=uu,next[edge]=first[vv],first[vv]=edge;}void dfs(int cur,int fa){ d[cur]=low[cur]=d[fa]+1; for (int i=first[cur]; i!=-1; i=next[i]) { if (to[i]==fa) continue; if (!d[to[i]]) { if (fa==0) child++; dfs(to[i],cur); low[cur]=min(low[cur],low[to[i]]); if (low[to[i]]>=d[cur]) iscut[cur]=true; } else low[cur]=min(low[cur],d[to[i]]); } if (fa==0 && child==1) iscut[cur]=false;}void visit(int cur,int TAG){ sum++,vis[cur]=true; for (int i=first[cur]; i!=-1; i=next[i]) { if (iscut[to[i]] && tag[to[i]]!=TAG) cut++,tag[to[i]]=TAG; else if (!iscut[to[i]] && !vis[to[i]]) visit(to[i],TAG); }}int main(){ int cas=0; while (scanf("%d",&m) && (m)) { n=0; for (int i=1; i<=m; i++) scanf("%d%d",&U[i],&V[i]),n=max(n,max(U[i],V[i])); _init(); for (int i=1; i<=m; i++) addedge(U[i],V[i]); for (int i=1; i<=n; i++) if (!d[i]) { child=0; dfs(i,0); } for (int i=1; i<=n; i++) if (!vis[i] && !iscut[i]) { cut=sum=0; visit(i,i); if (cut==0) tot+=2,ans*=(ll)sum*(sum-1)/2; else if (cut==1) tot++,ans*=sum; } printf("Case %d: %d %lld\n",++cas,tot,ans); } return 0;}