根据题意利用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 ",(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]]++; } } } } int ans=0; //计算度为1的点的个数 for(int i = 1;i <= n;i++) { if(cnt[i] == 1) ans++; } printf("%d ",(ans + 1) / 2); } return 0; }