博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[HNOI2012]矿场搭建(割点)
阅读量:4664 次
发布时间:2019-06-09

本文共 3062 字,大约阅读时间需要 10 分钟。

题目描述

煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口。

请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数。

输入格式

输入文件有若干组数据,每组数据的第一行是一个正整数 N(N<=500),表示工地的隧道数,接下来的 N 行每行是用空格隔开的两个整数 S 和 T,表示挖 S 与挖煤点 T 由隧道直接连接。输入数据以 0 结尾。

输出格式

输入文件中有多少组数据,输出文件 output.txt 中就有多少行。每行对应一组输入数据的 结果。其中第 i 行以 Case i: 开始(注意大小写,Case 与 i 之间有空格,i 与:之间无空格,: 之后有空格),其后是用空格隔开的两个正整数,第一个正整数表示对于第 i 组输入数据至少需 要设置几个救援出口,第二个正整数表示对于第 i 组输入数据不同最少救援出口的设置方案总 数。输入数据保证答案小于 2^64。输出格式参照以下输入输出样例。


 

#include
#define re return#define ll long long#define inc(i,l,r) for(int i=l;i<=r;++i) using namespace std;template
inline void rd(T&x){ char c;bool f=0; while((c=getchar())<'0'||c>'9')if(c=='-')f=1; x=c^48; while((c=getchar())>='0'&&c<='9')x=x*10+(c^48); if(f)x=-x;}const int maxn=5005,maxm=10005;ll n,m,k=1,rs,GD,tot,col,hd[maxn];ll low[maxn],dfn[maxn],isgd[maxn],vis[maxn];struct node{ int to,nt;}e[maxm<<1];ll ans1,ans=1;inline void add(int x,int y){ e[++k].to=y;e[k].nt=hd[x];hd[x]=k; e[++k].to=x;e[k].nt=hd[y];hd[y]=k;}stack
s;inline void tarjan(int x,int fa){ dfn[x]=low[x]=++tot; for(int i=hd[x];i;i=e[i].nt) { int v=e[i].to; if(v==fa)continue; if(!dfn[v]) { tarjan(v,x); low[x]=min(low[x],low[v]); if(!fa)++rs; else if(dfn[x]<=low[v])//割点 isgd[x]=1; } else low[x]=min(dfn[v],low[x]); }}inline void dfs(int x){ ++rs; vis[x]=col; for(int i=hd[x];i;i=e[i].nt) { int v=e[i].to; //如果是割点 且没算在此环内,GD+1 if(isgd[v]&&vis[v]!=col)++GD,vis[v]=col; //没有被访问过 else if(!vis[v]) dfs(v); }}int main(){ freopen("in.txt","r",stdin); int x,y,z,vv=0,maxx; rd(n); while(n) { k=1; maxx=col=tot=0; vv++; memset(vis,0,sizeof vis); memset(hd,0,sizeof hd); memset(dfn,0,sizeof dfn); memset(low,0,sizeof low); memset(isgd,0,sizeof isgd); inc(i,1,n) { rd(x),rd(y); maxx=max(maxx,max(x,y)); add(x,y); } //trajan找割点 inc(i,1,maxx) if(!dfn[i]) { rs=0; tarjan(i,0); if(rs>1)isgd[i]=1; } //Get_ans ans=1;ans1=0; inc(i,1,maxx) if(!vis[i]&&(!isgd[i])) { ++col; rs=GD=0; dfs(i); //如果不与割点相连 //环内任选两点以防止选一个点被毁 if(GD==0) { ans*=(rs-1)*rs/2; ans1+=2; } //如果只与一个割点相连 //环内需要一个点防止割点被毁 else if(GD==1) { ++ans1; ans*=rs; } //如果有两个及以上的割点 //任跑一个割点都可以走 } printf("Case %d: %lld %lld\n",vv,ans1,ans); rd(n); } re 0;}

 

转载于:https://www.cnblogs.com/lsyyy/p/11420709.html

你可能感兴趣的文章
56、剑指offer--删除链表中重复的结点
查看>>
QT5.0 国际化失败
查看>>
Mac 10.10 下安装jdk 1.7 以上
查看>>
制作SM2证书
查看>>
C++ set简介及简单应用
查看>>
【C#】 Socket通讯客户端程序
查看>>
第四章作业4
查看>>
MySQL-如何删除hash表分区
查看>>
eclipses新建maven项目xml第一行报错 什么没有,又下载不了
查看>>
Ibatis中返回一对多结果集的解决方法
查看>>
“匈牙利标记法”相关知识集结
查看>>
TCP: time wait bucket table overflow问题解决
查看>>
Ubuntu Phone开箱上手
查看>>
分布式系统常用思想和技术
查看>>
Tomcat7调试运行环境搭建与源代码分析入门
查看>>
C语言简单实现下载
查看>>
递归读取文件夹下的文件
查看>>
CodeForces Round 200 Div2
查看>>
HDU-2032
查看>>
总结day6 ---- set集合,基本类型的相互转化,编码,数据类型总结,循环时候不要动列表或者字典,深浅copy...
查看>>