[NOIP模拟][双连通分量]建设图
2017-10-24 16:18
253 查看
样例输入:
7 7
1 2
2 3
3 4
2 5
4 5
5 6
5 7
样例输入:
2
题目分析:
题目说要使得任何一条道路损坏后,任意两个城市也可以相互到达,这不就是双连通分量的定义吗,所以这道题就是要我们把原图加边加成一个双连通。再考虑原图,它可能含有一些双连通分量,这些双连通分量内部已经符合要求,只是与外面的点还不符合要求。那么可以先缩点,原图就成为了一棵树(题目保证原有道路可以使得所有城市连到)。于是问题转化为加最少的边将一棵树变成双连通的。通过画图发现,其实加的边数等于叶子节点数+1除以2。结论解释:叶子节点数是指那些连边个数为1的点;除法当然是指计算机int除法。注意,画图连边的方法,应该是将最左边的叶子节点和最右边的叶子节点相连,然后次左和次右连~~~,这样才是最优的。最后如何求叶子节点数,你可以dfs(注意根节点有可能就是一个叶子节点,并且有可能原图已经双连通了),也可以直接就统计缩点后那些点连的双连通分量外的边的个数。
附代码:
7 7
1 2
2 3
3 4
2 5
4 5
5 6
5 7
样例输入:
2
题目分析:
题目说要使得任何一条道路损坏后,任意两个城市也可以相互到达,这不就是双连通分量的定义吗,所以这道题就是要我们把原图加边加成一个双连通。再考虑原图,它可能含有一些双连通分量,这些双连通分量内部已经符合要求,只是与外面的点还不符合要求。那么可以先缩点,原图就成为了一棵树(题目保证原有道路可以使得所有城市连到)。于是问题转化为加最少的边将一棵树变成双连通的。通过画图发现,其实加的边数等于叶子节点数+1除以2。结论解释:叶子节点数是指那些连边个数为1的点;除法当然是指计算机int除法。注意,画图连边的方法,应该是将最左边的叶子节点和最右边的叶子节点相连,然后次左和次右连~~~,这样才是最优的。最后如何求叶子节点数,你可以dfs(注意根节点有可能就是一个叶子节点,并且有可能原图已经双连通了),也可以直接就统计缩点后那些点连的双连通分量外的边的个数。
附代码:
#include<iostream> #include<cstring> #include<string> #include<cstdlib> #include<cstdio> #include<ctime> #include<cmath> #include<cctype> #include<iomanip> #include<algorithm> #include<queue> using namespace std; const int N=1e5+100; const int M=2e5+100; int tot,first ,nxt[M*2],to[M*2],times,top,cnt,pd ,dfn ,low ,po; int ans,sum,stack ,n,m,maxnum,num ; bool flag ; int readint() { char ch;int i=0,f=1; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-') {ch=getchar();f=-1;} for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0'; ae3e return i*f; } void create(int x,int y) { tot++; nxt[tot]=first[x]; first[x]=tot; to[tot]=y; } void dfs_tarjan(int u,int from) { times++; dfn[u]=times; low[u]=times; stack[top++]=u; for(int e=first[u];e;e=nxt[e]) { int v=to[e]; if(dfn[v]==0) { dfs_tarjan(v,e); low[u]=min(low[u],low[v]); } else if((e^1)!=from) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { cnt++; while(top>=1&&stack[top]!=u) { top--; pd[stack[top]]=cnt;//缩点 } } } int main() { freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); int x,y; n=readint();m=readint(); tot=1; for(int i=1;i<=m;i++) { x=readint();y=readint(); create(x,y); create(y,x); } dfs_tarjan(1,0);//tarjan求双连通 tot=0; for(int i=1;i<=n;i++) { for(int e=first[i];e;e=nxt[e]) { int v=to[e]; if(pd[v]!=pd[i]&&flag[v]==false)//记录缩点后的点连的边数 { num[pd[i]]++; num[pd[v]]++; } } flag[i]=true; } for(int i=1;i<=cnt;i++) if(num[i]==1) sum++;//统计叶子节点个数 if(sum%2==1) ans=sum/2+1; else ans=sum/2;//其实偶数可以和奇数合成一步,+1对于偶数不影响答案 printf("%d",ans); return 0; }
相关文章推荐
- NOIP模拟(10.24)T1 建设图
- jzoj 2568. 【NOIP2011模拟9.17】地铁建设
- 【NOIP2011模拟9.17】地铁建设
- NOIp模拟 电缆建设
- 2568. 【NOIP2011模拟9.17】地铁建设 (Standard IO)
- [NOIP2017模拟]建设图
- NOIP2014提高组模拟题 8.9
- NOIP模拟 Board
- [NOIP模拟] 匹配
- 【NOIP2015模拟10.28B组】终章-剑之魂
- 【2016.10.4NOIP普及模拟】Exam
- 3917 【NOIP2014模拟11.2A组】福慧双修 (Standard IO)题解
- [NOIP模拟]购买板凳
- 2069. 【2016.10.5NOIP普及模拟】wd的假日
- NOIP2017 赛前模拟 7.24
- 【JZOJ 4314】【NOIP2015模拟11.4】老司机
- NOIP模拟 171019总结
- noip2011 玛雅游戏 大模拟
- 【jzoj】2018/2/2 NOIP普及组——D组模拟赛
- jzoj3797 [NOIP2014模拟8.21] 签到题3