牛客小白月赛12 I (tarjan求割边)

题目链接:https://ac.nowcoder.com/acm/contest/392/I

题目大意:一个含有n个顶点m条边的图,求经过所有顶点必须要经过的边数。

例:

输入:

5 5
1 2
2 3
3 4
4 5
3 5

输出:

3

解题思路:比赛的时候想的是,如果一个顶点不在环里,那与它相连的边就必定是一定要经过的边,所有可以用拓扑排序把不在环上的顶点进行统计一下,每去一个顶点必定去掉一条边,所以我们可以用总的边数减去不在环上的点的个数,不过这有个问题就是当有n个顶点,n-1条边的时候,产生的结果会是-1,开始没考虑这种情况WA了两发,我们只需要把答案和0取个最大值就好了。

然后就是出的题解用的是tarjan,显然必要的边是割边,我们用总边数减去割边数就可以了。

Tarjan做法:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=300005;
int n,m,head[maxn],par[maxn],dfn[maxn],low[maxn],tot,cnt,ans;
struct node{
    int to,next;
}edge[2*maxn];
void add(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
void Tarjan(int u){
    dfn[u]=low[u]=++cnt;
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if(!dfn[v]){
            par[v]=u;
            Tarjan(v);
            if(low[v]>dfn[u]) ans++;
            low[u]=min(low[u],low[v]);
        }
        else if(v!=par[u]) low[u]=min(low[u],dfn[v]);
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)head[i]=-1;
    for(int i=1;i<=m;i++){
        int u,v;
        cin>>u>>v;
        add(u,v);
        add(v,u);
    }
    Tarjan(1);
    cout<<m-ans<<endl;
    return 0;
}

拓扑做法:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<set>
#include<cmath>
#include<list>
#include<deque>
#include<cstdlib>
#include<bitset>
#include<stack>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define pushup() tree[rt]=tree[rt<<1]+tree[rt<<1|1]
const int INF=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-6;
const ll mod=10007;
const int maxn=1000005;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
const int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int n,m,in[100005],sum;
vector<int> mp[100005];
void topsort(){
    queue<int> que;
    for(int i=1;i<=n;i++){
        if(in[i]==1){
            que.push(i); sum++;
        }
    }
    while(que.size()){
        int u=que.front();
        que.pop();
        int size=mp[u].size();
        for(int i=0;i<size;i++){
            int v=mp[u][i];
            in[v]--;
            if(in[v]==1){
                que.push(v);
                sum++;
            }
        }
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        mp[u].push_back(v);
        mp[v].push_back(u);
        in[u]++; in[v]++;
    }
    topsort();
    int ans=max(m-sum,0);
    cout<<ans<<endl;
    return 0;
}

 

posted @ 2019-03-12 16:47  两点够吗  阅读(347)  评论(0编辑  收藏  举报