题意:某个企业想把一个热带天堂岛变成旅游胜地,岛上有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;
}
转载于:https://blog.51cto.com/8590696/1358876