2730: [HNOI2012]矿场搭建

来源:互联网 发布:知已的近义词 编辑:程序博客网 时间:2024/04/30 06:02

点-双联通分量。

显然割顶不放,一个双联通分量若有多个割顶,也不用放,剩下的就是乘法原理了。

特判:原图是双联通的,任意找两个点放就好了。

WF2011原题。

#include<iostream>#include<cstdio>#include<cstring>#include<stack>#include<vector>using namespace std;const int N=500+5;typedef long long ll;struct Edge{int to,next;}e[N*2];struct edge{int u,v;};int head[N],cnt,bcc_cnt,bccno[N],pre[N],dfs_clock;stack<edge>s;vector<int>bcc[N];bool iscut[N];void ins(int u,int v){cnt++;e[cnt].to=v;e[cnt].next=head[u];head[u]=cnt;}int dfs(int u,int fa){int lowu=pre[u]=++dfs_clock;int child=0;for(int i=head[u];i;i=e[i].next){int v=e[i].to;if(!pre[v]){s.push((edge){u,v});child++;int lowv=dfs(v,u);lowu=min(lowu,lowv);if(lowv>=pre[u]){iscut[u]=true;bcc_cnt++;bcc[bcc_cnt].clear();while(true){edge tmp=s.top();s.pop();if(bccno[tmp.u]!=bcc_cnt)bccno[tmp.u]=bcc_cnt,bcc[bcc_cnt].push_back(tmp.u);if(bccno[tmp.v]!=bcc_cnt)bccno[tmp.v]=bcc_cnt,bcc[bcc_cnt].push_back(tmp.v);if(tmp.u==u&&tmp.v==v)break;}}}else if(pre[v]<pre[u]&&v!=fa){s.push((edge){u,v});lowu=min(lowu,pre[v]);}}if(fa<0&&child==1)iscut[u]=false;return lowu;}void find_bcc(int n){memset(pre,0,sizeof(pre));memset(iscut,false,sizeof(iscut));memset(bccno,0,sizeof(bccno));dfs_clock=bcc_cnt=0;for(int i=1;i<=n;i++)if(!pre[i])dfs(i,-1);}int main(){int n,kase=0;while(scanf("%d",&n)&&n){int u,v,node=0;memset(head,0,sizeof(head));cnt=0;for(int i=1;i<=n;i++){scanf("%d%d",&u,&v);ins(u,v);ins(v,u);node=max(node,u);node=max(node,v);}find_bcc(node);ll ans1=0,ans2=1;if(bcc_cnt==1){ans1=2;ans2=bcc[1].size()*(bcc[1].size()-1)/2;}else{for(int i=1;i<=bcc_cnt;i++){int cut_cnt=0;for(int j=0;j<bcc[i].size();j++)if(iscut[bcc[i][j]])cut_cnt++;if(cut_cnt==1){ans1++;ans2*=(ll)(bcc[i].size()-cut_cnt);}}}printf("Case %d: %lld %lld\n",++kase,ans1,ans2);}return 0;}


0 0
原创粉丝点击