POJ-3352 Road Construction

Posted on 2021-12-09 17:24  Capterlliar  阅读(20)  评论(0编辑  收藏  举报

题意:给出一张无向图,求添加多少条边后任意减去一条边,整张图仍联通。

解:第一个想到的是割边,想对于一条割边,将上下两点连起来,所以输出割边的数量。画了画图觉得不对,对于一条链,把两头连起来就满足要求了,应该求这张图有多少线头,然后把线头数量除以2。然后删掉割边的代码,写着写着发现和上一题相同起来……割点割边碰到了再练吧。

注意这次是无向图,所以不能求出度为0,应该求出度为1.

代码:

#include <algorithm>
#include <stack>
#include <vector>
#include <stdio.h>
using namespace std;
#define maxx 10005
#define maxn 10005
#define maxm 50005
#define inf 0x3f3f3f3f
int n,m;
vector<int> e[maxm];
int dfn[maxn]={0},low[maxn]={0};
int cnt=0,vis[maxn]={0};
int colornum=0,color[maxn]={0},num[maxn]={0};
int out[maxn]={0};
stack<int> s;
void paint(int x){
    s.pop();
    vis[x]=0;
    color[x]=colornum;
    num[colornum]++;
}
void tarjan(int now,int fa){
    s.push(now);
    vis[now]=1;
    low[now]=dfn[now]=++cnt;
    for(int i=0;i<e[now].size();i++){
        int to=e[now][i];
        if(to==fa)
            continue;
        if(!dfn[to]){
            tarjan(to,now);
            low[now]=min(low[now],low[to]);
        }
        else if(vis[to])
            low[now]=min(low[now],dfn[to]);
    }
    if(low[now]==dfn[now]){
        colornum++;
        while (s.top()!=now)
            paint(s.top());
        paint(now);
    }
}
signed main() {
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        e[x].push_back(y);
        e[y].push_back(x);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i,0);
    for(int i=1;i<=n;i++){
        for(int j=0;j<e[i].size();j++){
            int to=e[i][j];
            if(color[to]!=color[i])
                out[color[i]]++;
        }
    }
    int ans=0;
    for(int i=1;i<=colornum;i++)
        if(out[i]==1){
            ans++;
        }
    printf("%d\n",(ans+1)/2);
    return 0;
}
View Code