洛谷—— P3225 [HNOI2012]矿场搭建

https://www.luogu.org/problem/show?pid=3225

题目描述

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

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:

9
1  3
4  1
3  5
1  2
2  6
1  5
6  3
1  6
3  2
6
1  2
1  3
2  4
2  5
3  6
3  7
0

输出样例#1:

Case 1: 2 4
Case 2: 4 1

说明

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

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

很明显需要求出割点。屏蔽割点后、

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

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

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

 1 #include <cstring>
 2 #include <cstdio>
 3
 4 const int N(555);
 5 int head[N],sumedge=1;
 6 struct Edge
 7 {
 8     int v,next;
 9     Edge(int v=0,int next=0):v(v),next(next){}
10 }edge[N*N/2];
11 inline void ins(int u,int v)
12 {
13     edge[++sumedge]=Edge(v,head[u]);
14     head[u]=sumedge;
15     edge[++sumedge]=Edge(u,head[v]);
16     head[v]=sumedge;
17 }
18
19 #define max(a,b) (a>b?a:b)
20 #define min(a,b) (a<b?a:b)
21 int tim,dfn[N],low[N];
22 int cutpoint[N];
23 void Tarjan(int u,int pre)
24 {
25     dfn[u]=low[u]=++tim;
26     int sumtredge=0,if_point=0;
27     for(int v,i=head[u];i;i=edge[i].next)
28     {
29         v=edge[i].v;
30         if((i^1)==pre) continue;
31         if(!dfn[v])
32         {
33             sumtredge++;
34             Tarjan(v,i);
35             if(low[v]>=dfn[u]) if_point=1;
36             low[u]=min(low[u],low[v]);
37         }
38         else low[u]=min(low[u],dfn[v]);
39     }
40     if(!pre)
41     {
42         if(sumtredge>1) cutpoint[u]=1;
43     }
44     else if(if_point) cutpoint[u]=1;
45 }
46
47 int sumcol,point,cnt,vis[N],col[N];
48 void DFS(int u)
49 {
50     point++;
51     vis[u]=1;
52     col[u]=sumcol;
53     for(int v,i=head[u];i;i=edge[i].next)
54     {
55         v=edge[i].v;
56         if(cutpoint[v]&&col[v]!=sumcol) cnt++,col[v]=sumcol;
57         if(!vis[v]&&!cutpoint[v]) DFS(v);
58     }
59 }
60
61 inline void init()
62 {
63     tim=sumcol=0; sumedge=1;
64     memset(dfn,0,sizeof(dfn));
65     memset(col,0,sizeof(col));
66     memset(vis,0,sizeof(vis));
67     memset(low,0,sizeof(low));
68     memset(head,0,sizeof(head));
69     memset(edge,0,sizeof(edge));
70     memset(cutpoint,0,sizeof(cutpoint));
71 }
72
73 int main()
74 {
75     for(int m,n=0,k=1;scanf("%d",&m)&&m;k++,n=0,init())
76     {
77         for(int u,v;m--;ins(u,v))
78             scanf("%d%d",&u,&v),n=max(n,max(u,v));
79         for(int i=1;i<=n;i++)
80             if(!dfn[i]) Tarjan(i,0);
81         long long ans_sum=1;
82         int ans_cnt=0;
83         for(int i=1;i<=n;i++)
84         {
85             if(vis[i]||cutpoint[i]) continue;
86             point=cnt=0;
87             sumcol++,DFS(i);
88             if(!cnt) ans_cnt+=2,ans_sum*=(long long)(point*(point-1)>>1);
89             if(cnt==1) ans_cnt++,ans_sum*=(long long)point;
90         }
91         printf("Case %d: %d %lld\n",k,ans_cnt,ans_sum);
92     }
93     return 0;
94 }
时间: 2024-11-05 15:59:49

洛谷—— P3225 [HNOI2012]矿场搭建的相关文章

洛谷——P3225 [HNOI2012]矿场搭建

P3225 [HNOI2012]矿场搭建 题目描述 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口. 请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数. 输入输出格式 输入格式: 输入文件有若干组数据,每组数据的第一行是一个正整数 N(N<=500),表示工地的隧道数,接下来的

BZOJ 2730:[HNOI2012]矿场搭建(割点+连通块)

[HNOI2012]矿场搭建 Description 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口.请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数.Input 输入文件有若干组数据,每组数据的第一行是一个正整数 N(N≤500),表示工地的隧道数,接下来的 N 行每行是用空

[HNOI2012]矿场搭建 题解

[HNOI2012]矿场搭建 时间限制: 1 Sec  内存限制: 128 MB 题目描述 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口.请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数. 输入 输入文件有若干组数据,每组数据的第一行是一个正整数 N(N≤500),表示工地的

cogs——1348. [HNOI2012]矿场搭建

1348. [HNOI2012]矿场搭建 ★★★   输入文件:bzoj_2730.in   输出文件:bzoj_2730.out   简单对比时间限制:1 s   内存限制:128 MB [题目描述] 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口.请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少

[HNOI2012]矿场搭建

明明是Acm World Finals 2011的原题,把数据范围改小了就放出来了?!这样不好,, 昨天讲完双连通分量今天A一道点双的题. Description 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口.请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数. Input 输

bzoj 2730: [HNOI2012]矿场搭建

Description 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口.请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数. Input 输入文件有若干组数据,每组数据的第一行是一个正整数 N(N≤500),表示工地的隧道数,接下来的 N 行每行是用空格隔开的两个整数 S 和 T

[BZOJ2730][HNOI2012]矿场搭建(求割点)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2730 分析: 如果坍塌的点不是割点,那没什么影响,主要考虑坍塌的点是割点的情况. 显然我们可以先求出所有割点把整个图分成若干个连通块 如果一个联通块只与一个割点相连,说明我们必须在这个连通块中选一个点作为出口 如果一个联通块与两个以上的割点相连,那么就可以不在这些点取一个作为出口 方案数就是要取点的联通块的点的个数的乘积 注意没有割点的情况要放2个点

【BZOJ 2730】 [HNOI2012]矿场搭建

Description 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口.请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数. Input 输入文件有若干组数据,每组数据的第一行是一个正整数 N(N≤500),表示工地的隧道数,接下来的 N 行每行是用空格隔开的两个整数 S 和 T

bzoj2730: [HNOI2012]矿场搭建

Description 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口.请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数. Input 输入文件有若干组数据,每组数据的第一行是一个正整数 N(N≤500),表示工地的隧道数,接下来的 N 行每行是用空格隔开的两个整数 S 和 T