根据题意利用tarjan算法进行缩点处理后变成连通无环图,也可以说是一颗树,而且边是双向的所以,如果把这个图变成双连通,那就要对所有度为1的点进行加边处理
所以步骤如下
1·tarjan缩点处理
void tarjan(int u,int pre)
{
low[u] = dfn[u] = ++idx;
for(int v = 1;v <= n;v++)
{
if(mp[u][v])
{
if(!dfn[v])
{
tarjan(v,u);
low[u] = min(low[u],low[v]);
}
if(dfn[v] && v != pre)
{
low[u] = min(low[u],dfn[v]);
}
}
}
}
2· 计算点的度
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= n;j++)//计算每个点的度
{
if(mp[i][j])
{
if(low[i] != low[j])
{
cnt[low[j]]++;
}
}
}
}
3·计算加的边数
int ans=0; //计算度为1的点的个数
for(int i = 1;i <= n;i++)
{
if(cnt[i] == 1) ans++;
}
printf("%d\n",(ans + 1) / 2);
嗯嗯tarjan算法差不多啦
这个题目还出了一个小插曲,就是定义mp时候用的int类型,给爆了,改成bool就好了,其实就该用bool,因为只是一个01存储,但是一想bool和int差的可不是1倍两倍,而是32倍呢(还得看编译器),吓人略略略
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn = 5010;
int n,m;
bool mp[maxn][maxn];
int low[maxn],dfn[maxn];
int idx;
int cnt[maxn];
/*
bool 类型的数据 在内存中只有一位 或0 或1
int 类型的数据 在内存中有16位或32位
*/
void init()
{
memset(low,0,sizeof(low));
memset(mp,0,sizeof(mp));
memset(dfn,0,sizeof(dfn));
memset(cnt,0,sizeof(cnt));
idx = 0;
}
void tarjan(int u,int pre)
{
low[u] = dfn[u] = ++idx;
for(int v = 1;v <= n;v++)
{
if(mp[u][v])
{
if(!dfn[v])
{
tarjan(v,u);
low[u] = min(low[u],low[v]);
}
if(dfn[v] && v != pre)
{
low[u] = min(low[u],dfn[v]);
}
}
}
}
int main()
{
int u,v;
while(~scanf("%d%d",&n,&m))
{
init();
for(int i = 1;i <= m;i++)
{
scanf("%d%d",&u,&v);
mp[u][v] = mp[v][u] = 1;
}
tarjan(1,1);
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= n;j++)//计算每个点的度
{
if(mp[i][j])
{
if(low[i] != low[j])
{
cnt[low[j]]++;
}
}
}
}
}
return 0;
}