博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洛谷——P3225 [HNOI2012]矿场搭建
阅读量:6568 次
发布时间:2019-06-24

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

P3225 [HNOI2012]矿场搭建

题目描述

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

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

输入输出格式

输入格式:

 

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

 

输出格式:

 

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

 

输入输出样例

输入样例#1:
91  34  13  51  22  61  56  31  63  261  21  32  42  53  63  70
输出样例#1:
Case 1: 2 4Case 2: 4 1

说明

Case 1 的四组解分别是(2,4),(3,4),(4,5),(4,6);

Case 2 的一组解为(4,5,6,7)。

 

分情况讨论:

很显然是要求割点嘛、、、(分类上写着、、、)

好吧,求完割点以后干什么??

我一直认为是先求出割点,然后将割点全部炸掉(屏蔽)后求出每个联通块的点的个数,然后在用乘法原理来做。

结果发现全wa!!!(ORZ)

据说这道题要分类讨论、、、、

①若一个双联通中没有割点,那么最少需要两个出口(炸了一个去另一个)

②若一个双联通能连到一个割点,那么最少需要在双联通中设置一个出口,炸了割点还能逃生、

③若一个双联通能连到多余一个割点,那么不管怎么炸,都能从没炸的割点跑到别的分量里

#include
#include
#include
#include
#include
#define N 510using namespace std;long long ans2;bool vis[N],cut_point[N];int n,m,x,y,s,tot,tim,cnt,cut,sum,ans1;int dfn[N],low[N],head[N],belong[N];int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){
if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f;}struct Edge{ int from,to,next;}edge[N<<1];int add(int x,int y){ tot++; edge[tot].to=y; edge[tot].next=head[x]; head[x]=tot;}int begin(){ memset(vis,0,sizeof(vis)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(edge,0,sizeof(edge)); memset(head,0,sizeof(head)); memset(belong,0,sizeof(belong)); memset(cut_point,0,sizeof(cut_point)); n=0,tot=1,ans1=0,ans2=1,tim=0,sum=0;}int tarjan(int now,int pre){ dfn[now]=low[now]=++tim; int tt=0; bool boo=false; for(int i=head[now];i;i=edge[i].next) { int t=edge[i].to; if((1^i)==pre) continue; if(!dfn[t]) { tt++;tarjan(t,i); low[now]=min(low[now],low[t]); if(dfn[now]<=low[t]) boo=true; } else low[now]=min(low[now],dfn[t]); } if(pre==-1) {
if(tt>1) cut_point[now]=true;} else if(boo) cut_point[now]=true; }int dfs(int x){ s++; vis[x]=true; belong[x]=sum; for(int i=head[x];i;i=edge[i].next) { int t=edge[i].to; if(cut_point[t]&&belong[t]!=sum) cut++,belong[t]=sum; if(!vis[t]&&!cut_point[t]) dfs(t); }}int main(){ while(1) { m=read();if(m==0) break; begin(); for(int i=1;i<=m;i++) { x=read(),y=read(); add(x,y),add(y,x); n=max(max(x,y),n); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,-1); for(int i=1;i<=n;i++) { if(vis[i]||cut_point[i]) continue; s=0,cut=0; sum++;dfs(i); if(!cut) ans1+=2,ans2*=(long long)(s*(s-1)>>1); if(cut==1) ans1++,ans2*=(long long)s; } printf("Case %d: %d %lld\n",++cnt,ans1,ans2); } return 0;}

 

傻不拉几的只考虑一种情况还调试半天、、、、结果全wa

#include
#include
#include
#include
#include
#define N 11000using namespace std;bool vis[N],cut_point[N];int n,m,tot,tim,sum,cnt,top,ans1,ans2;int x[N],y[N],dfn[N],low[N],ans[N],head[N],stack[N],belong[N];int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){
if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f;}struct Edge{ int from,to,next;}edge[N];int add(int x,int y){ tot++; edge[tot].to=y; edge[tot].next=head[x]; head[x]=tot;}int tarjan(int x,int pre){ int s=0; bool boo; dfn[x]=low[x]=++tim; vis[x]=true; for(int i=head[x];i;i=edge[i].next) { int t=edge[i].to; if((1^i)==pre) continue; if(!vis[t]) { s++;tarjan(t,i); low[x]=min(low[t],low[x]); if(low[t]>=dfn[x]) boo=true; } else low[x]=min(low[x],dfn[t]); } if(!pre) {
if(s>1) cut_point[x]=true;} else {
if(boo) cut_point[x]=true;}}int tarjan1(int now){ dfn[now]=low[now]=++tim; stack[++top]=now;vis[now]=true; for(int i=head[now];i;i=edge[i].next) { int t=edge[i].to; if(vis[t]) low[now]=min(low[now],dfn[t]); else if(!dfn[t]) tarjan1(t),low[now]=min(low[now],low[t]); } if(dfn[now]==low[now]) { sum++; belong[now]=sum;ans[sum]++; for(;stack[top]!=now;top--) belong[stack[top]]=sum,vis[stack[top]]=false,ans[sum]++; vis[now]=false; top--; }}int begin(){ tot=0,tim=0,sum=0,ans2=1; memset(ans,0,sizeof(ans)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(vis,0,sizeof(vis)); memset(head,0,sizeof(head)); memset(belong,0,sizeof(belong));}int main(){ while(1) { m=read();if(m==0) break; begin();cnt++,tot=1; memset(cut_point,0,sizeof(cut_point)); for(int i=1;i<=m;i++) x[i]=read(),y[i]=read(),add(x[i],y[i]),add(y[i],x[i]); tarjan(1,0); begin(); for(int i=1;i<=m;i++) { n=max(max(x[i],y[i]),n); if(cut_point[x[i]]||cut_point[y[i]]) continue; add(x[i],y[i]),add(y[i],x[i]); } for(int i=1;i<=n;i++) if(!dfn[i]&&!cut_point[i]) tarjan1(i); ans1=sum; for(int i=1;i<=sum;i++) ans2*=ans[i]; printf("Case %d: %d %d\n",cnt,ans1,ans2); } return 0;}
View Code

 

转载于:https://www.cnblogs.com/z360/p/7462485.html

你可能感兴趣的文章
MySQL-MMM实现MySQL高可用
查看>>
看菲菲详解如何快速获取linux命令帮助
查看>>
vim 编辑器详解
查看>>
现代软件工程 第十章 【典型用户和场景】 练习与讨论
查看>>
Linux如何编译安装源码包软件
查看>>
MySQL备份类型
查看>>
仿腾讯网的JS图片切换代码
查看>>
升级centos6.6至centos7.2.1511
查看>>
postgresql创建表
查看>>
springMVC参数传递(三)
查看>>
说说Keepalived的脑裂
查看>>
linux 学习总结
查看>>
CentOS6.4下安装xampp
查看>>
shell语法
查看>>
从某次测试过程中,得到的MySQL性能优化的建议,和定位问题的方法
查看>>
JS三大对象中常用方法集锦
查看>>
词汇与分词技术
查看>>
SVN安装部署方案(一)
查看>>
我的友情链接
查看>>
CentOS7.4下建立DNS主从服务器(二)
查看>>