博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
loj 1308(点双连通分量应用)
阅读量:4690 次
发布时间:2019-06-09

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

题目链接:

题意:求一个连通图去掉任意一个点以及与它相连的边,图中的所有蚂蚁可以通过某些点中建造的矿井逃到地面,求最少要在图中的几个点中建造矿建,这样建造矿井的方案的总数。

思路:首先求点双连通分量,标记割点,然后我们可以分析,若一个连通分量中有且仅有一个割点,那么除了这个割点之外,别的点都能造矿井,且只需在除了这个割点之外的某个点上造一座矿井就可以了(假设破话的是这个割点,那么这个连通分量中的蚂蚁可以通过有矿井的点逃到表面,但是如果矿井恰好造在割点上,那么一旦去掉了割点之后,蚂蚁就无法逃到地面上去了(这就是为什么不选割点的原因)。至于为什么别的点可以呢,假设破话的点恰好就是有矿井的这个点,那么这个连通分量中的蚂蚁可以通过割点跑到别的点双连通分量中逃生)。然后我们就只需要找有且只有一个割点的点双连通分量有多少个就行了,然后在每个连通分量中选择任何一个不是割点的点建造矿井就行了,至于有多少种方案,也就好求了,直接连通分量的点的个数(除去割点)相乘即可。然后我想说一下为什么对于那些点连通分量中割点大于等于2的就不用选呢,其实我们画一下图就知道了,因为破话这个连通分量的任何一个点以及与它相连的边,这个连通分量的中蚂蚁还是可以通过其中一个割点跑到另一个连通分量中去逃生。这样我们就得到了割点数目等于1和大于等于2的情况,那么对于图中没有割点的情况我们应该怎么选,这也好办,画个图就明白了,只需任选两个点建造矿井就可以了,当破话了某个有矿井的点之后,蚂蚁可以通过另一个有矿井的点逃生,那么总的方案数为n*(n-1)/2。

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 using namespace std; 9 #define MAXN 22222 10 typedef long long ll; 11 typedef unsigned long long llu; 12 13 struct Edge{ 14 int v,next; 15 }edge[MAXN<<1]; 16 17 int n,m,NE; 18 int head[MAXN]; 19 20 void Insert(int u,int v) 21 { 22 edge[NE].v=v; 23 edge[NE].next=head[u]; 24 head[u]=NE++; 25 } 26 27 int cnt,bcc_count,cut_count; 28 int low[MAXN],dfn[MAXN]; 29 vector
>blocks; 30 bool mark[MAXN]; 31 bool is_cutpoint[MAXN]; 32 stack
S; 33 34 void Tarjan(int root,int u,int father) 35 { 36 int rt_son=0; 37 low[u]=dfn[u]=++cnt; 38 mark[u]=true; 39 S.push(u); 40 for(int i=head[u];i!=-1;i=edge[i].next){ 41 int v=edge[i].v; 42 if(v==father)continue; 43 if(dfn[v]==0){ 44 Tarjan(root,v,u); 45 low[u]=min(low[u],low[v]); 46 if(u==root)rt_son++; 47 if(low[v]>=dfn[u]){ 48 int x; 49 do{ 50 x=S.top(); 51 S.pop(); 52 mark[x]=false; 53 blocks[bcc_count].push_back(x); 54 }while(v!=x); 55 blocks[bcc_count].push_back(u); 56 bcc_count++; 57 if(u!=root)is_cutpoint[u]=true; 58 } 59 }else if(mark[v]){ 60 low[u]=min(low[u],dfn[v]); 61 } 62 } 63 if(u==root&&rt_son>=2)is_cutpoint[u]=true; 64 } 65 66 int main() 67 { 68 int _case,u,v,t=1; 69 scanf("%d",&_case); 70 while(_case--){ 71 scanf("%d%d",&n,&m); 72 NE=0; 73 memset(head,-1,sizeof(head)); 74 blocks.clear(); 75 blocks.resize(n+2); 76 while(!S.empty())S.pop(); 77 while(m--){ 78 scanf("%d%d",&u,&v); 79 Insert(u,v); 80 Insert(v,u); 81 } 82 cnt=bcc_count=0; 83 memset(mark,false,sizeof(mark)); 84 memset(is_cutpoint,false,sizeof(is_cutpoint)); 85 memset(dfn,0,sizeof(dfn)); 86 Tarjan(0,0,-1); 87 ll ans=0; 88 llu ways=1; 89 int cut_count=0; 90 for(int i=0;i
View Code

 

转载于:https://www.cnblogs.com/wally/p/3339793.html

你可能感兴趣的文章
win7-64 mysql的安装
查看>>
dcm4chee 修改默认(0002,0013) ImplementationVersionName
查看>>
maven3在eclipse3.4.2中创建java web项目
查看>>
发布时间 sql语句
查看>>
黑马程序员 ExecuteReader执行查询
查看>>
记一些从数学和程序设计中体会到的思想
查看>>
题目1462:两船载物问题
查看>>
POJ 2378 Tree Cutting(树形DP,水)
查看>>
第二冲刺阶段个人博客5
查看>>
UVA 116 Unidirectional TSP (白书dp)
查看>>
第三方测速工具
查看>>
MySQL 网络访问连接
查看>>
在aws ec2上使用root用户登录
查看>>
数据访问 投票习题
查看>>
CIO知识储备
查看>>
cnblog!i'm coming!
查看>>
使用点符号代替溢出的文本
查看>>
Axios 中文说明
查看>>
fatal: remote origin already exists.
查看>>
gridview 自定义value值
查看>>