博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Graph_Master(连通分量_G_Trajan+Thought)
阅读量:4497 次
发布时间:2019-06-08

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

题目大意:给出m条边(隧道,无向),每条边连接两个点(矿场)。要在这些矿场中建设救援出口,防止矿场坍塌造成人员伤亡,问最少需要几个救援出口,以及对应方案数。(假设最多塌陷一个矿场)。

题解:这个题面给的数据比较良心,画画图知道需要找割点,然后把割点去掉跑连通块。也就是说每个连通块的颜色除了割点都是一样的,因为割点还属于别的连通块。紧接着就是统计答案了:

1、如果一个连通块没有割点,那么救援点至少建两个,方案数将乘上(这个连通块大小设为totv,包括割点)totv*(totv-1)/2,即C(2,totv)。建两个是以防如果只建一个,那个点坍塌了,就困死了,因为没有割点,就相当于是独立的,只能自生自灭。
2、如果一个连通块只有一个割点,那么救援点至少建一个,方案数乘上totv。因为如果割点坍塌,可以从救援点跑,如果救援点坍塌,可以从割点跑到另外的有救援点的连通块。
3、如果一个连通块有>=2个割点,不用建救援点,不用算方案数,因为不管怎么坍塌,都可以跑到别的有救援点的连通块。
(上图比较好理解)

1329707-20180913005308990-904352680.jpg

图解:1、2、3、47、8、9、10即为仅有一个割点(割点分别为4、7)的连通块。

4、5、6、7为有两个割点(4、7)的连通块。
11、12、13、14为没有割点的连通块(独立出来的一部分)。
有了图解每个连通块应该建几个救援点,以及如何统计方案数可以说就比较清楚了。

WA了很多发,因为没有发现used[]开成了bool,而却是用于染色,应该开成int,太粗心了。可以看到数组都远超所给范围,因为前几天给坑怕了。。


#include 
#include
#include
#include
#include
#define clr(a,b) memset((a),(b),sizeof(a))using namespace std;const int N = 10005;const int M = 1e6 + 16;typedef long long ll;struct Edge{ int nxt, u, v;};Edge edge[M];int ecnt, head[N];int low[N], dfn[N];int dep, col, cut_sum, totv;int used[N], iscut[N];int rt;void init(){ clr(head,-1); clr(used,0); clr(iscut,0); clr(dfn,0); clr(low,0); ecnt = dep = col = 0;}void _add( int a, int b ){ edge[ecnt].u = a; edge[ecnt].v = b; edge[ecnt].nxt = head[a]; head[a] = ecnt ++;}void tarjan( int u, int pr ){ low[u] = dfn[u] = ++dep; int son = 0; for ( int i = head[u]; i+1; i = edge[i].nxt ) { int v = edge[i].v; if ( v == pr ) continue; if ( !dfn[v] ) { son ++; tarjan( v, u ); low[u] = min( low[u], low[v] ); if ( low[v] >= dfn[u] ) iscut[u] = 1; } else low[u] = min( low[u], dfn[v] ); } if ( u == rt && son == 1 ) iscut[u] = 0;}void dfs( int u ){ used[u] = col; totv ++; for ( int i = head[u]; i+1; i = edge[i].nxt ) { int v = edge[i].v; if ( iscut[v] && used[v] != col ) { cut_sum++; used[v] = col; } else if ( !used[v] ) dfs( v ); }}int main(){ int m; int cas = 1; while ( scanf("%d", &m), m ) { int n = 0; init(); for ( int i = 0; i < m; i ++ ) { int u, v; scanf("%d%d", &u, &v); _add(u,v); _add(v,u); n = max( n, max(u,v) ); } for ( int i = 1; i <= n; i ++ ) { if ( !dfn[i] ) { rt = i; tarjan( i, -1 ); } } int ans1 = 0; ll ans2 = 1; for ( int i = 1; i <= n; i ++ ) { if ( !used[i] && !iscut[i] ) { totv = cut_sum = 0; col ++; dfs( i ); if ( cut_sum == 0 ) { ans1 += 2; ans2 *= 1ll*totv*(totv-1)/2; } else if ( cut_sum == 1 ) { ans1 ++; ans2 *= 1ll*totv; } } } printf("Case %d: %d %lld\n", cas++, ans1, ans2); } return 0;}

转载于:https://www.cnblogs.com/FormerAutumn/p/9638310.html

你可能感兴趣的文章
单片机 电子电路 嵌入式 毕设 课设 私活 代做
查看>>
notepad++ 安装 hex_editor 十六进制查看插件
查看>>
正则表达式
查看>>
Date类
查看>>
基本类型的数值转换
查看>>
集合、泛型、增强for
查看>>
Public Key Retrieval is not allowed错误
查看>>
Unable to load authentication plugin 'caching_sha2_password'.错误
查看>>
The server time zone value '乱码' 错误
查看>>
require.js的用法
查看>>
基础语言知识C++
查看>>
如何使电脑彻底崩溃!!!!(不要干坏事哦)
查看>>
简单练习题
查看>>
记账本,C,Github,service
查看>>
约数定理(two)
查看>>
Pyenv和pip的安装及配置
查看>>
字典dict
查看>>
squid-正向代理
查看>>
《A First Course in Probability》-chaper7-极限定理-强大数定理
查看>>
Python类型转换+序列操作+基本概念辨析速查手册
查看>>