题意:某个企业想把一个热带天堂岛变成旅游胜地,岛上有N个旅游景点,任意2个旅游景点之间有路径连通(注意不一定是直接连通)。而为了给游客提供更方便的服务,该企业要求道路部门在某些道路增加一些设施。
道路部门每次只会选择一条道路施工,在该条道路施工完毕前,其他道路依然可以通行。然而有道路部门正在施工的道路,在施工完毕前是禁止游客通行的。这就导致了在施工期间游客可能无法到达一些景点。为了在施工期间所有旅游景点依然能够正常对游客开放,该企业决定搭建一些临时桥梁,使得不管道路部门选在哪条路进行施工,游客都能够到达所有旅游景点。给出当下允许通行的R条道路,问该企业至少再搭建几条临时桥梁,才能使得游客无视道路部门的存在到达所有旅游景点?解题思路:赤裸裸的求边双连通缩点的题目,明显这是问至少加多少条边,才能把给出的图变成边双连通图,那么这题就是求边双连通图的构造问题了,又是很死很模板的事情了,直接用模板先求边双连通缩点,重构一个边双连通缩点树,那么这棵树的树叶数就是要加入的边数的一个指标了,(树叶数+1)/2就是要加入的边数了,一开始没注意,都是细节上的问题,自我测试时有几组数据没过,后来还是改好了,细节细节细节.....128msG++代码#include<iostream>#include<string>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring> #include<vector>#include<stack>using namespace std;vector<int>g[1005];int bn[1005][1005];stack<int>st;bool vis[1005];int dfn[1005],low[1005],n,m,ans,num,btch,d[1005],belone[1005];void tarjan(int i,int fa)
{ dfn[i]=low[i]=++num; vis[i]=true; st.push(i); int flag=1; for(int j=0;j<g[i].size();j++) { int v=g[i][j]; if(fa==v&&flag) { flag=0; continue; } if(!vis[v]) { tarjan(v,i); low[i]=min(low[v],low[i]); if(dfn[i]<low[v]) { int min=0,x; btch++; do { x=st.top(); belone[x]=btch; st.pop(); } while(x!=v); } } else low[i]=min(low[i],dfn[v]); }} int main(){ int i,x,y,j; while(scanf("%d %d",&n,&m)!=EOF) { num=btch=ans=0; for(i=0;i<=n;i++) { vis[i]=false; g[i].clear(); d[i]=0; belone[i]=0; } for(i=1;i<=m;i++) { scanf("%d %d",&x,&y); g[x].push_back(y); g[y].push_back(x); } tarjan(1,-1); memset(bn,0,sizeof(bn)); for(i=1;i<=n;i++) { for(j=0;j<g[i].size();j++) { int v=g[i][j]; if(belone[i]!=belone[v]&&(bn[belone[i]][belone[v]]==0&&bn[belone[v]][belone[i]]==0)) { d[belone[i]]++; d[belone[v]]++; bn[belone[i]][belone[v]]=bn[belone[v]][belone[i]]=1; } } }ans=0;
for(i=0;i<=btch;i++) { if(d[i]==1) ans++; } printf("%d\n",(ans+1)/2); } return 0;}