HDU-4587-TWO NODES(Tarjan求割点)

TWO NODES

Problem Description

Suppose that G is an undirected graph, and the value of stab is defined as follows:
在这里插入图片描述

Among the expression,G-i, -j is the remainder after removing node i, node j and all edges that are directly relevant to the previous two nodes. cntCompent is the number of connected components of X independently.
Thus, given a certain undirected graph G, you are supposed to calculating the value of stab.

Input

The input will contain the description of several graphs. For each graph, the description consist of an integer N for the number of nodes, an integer M for the number of edges, and M pairs of integers for edges (3<=N,M<=5000).
Please note that the endpoints of edge is marked in the range of [0,N-1], and input cases ends with EOF.

Output

For each graph in the input, you should output the value of stab.

Sample Input

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

Sample Output

2
 

解题思路:

要求删掉两个点的连通分量,那么先枚举删掉一个点(不访问就行了),然后再对剩下的子图跑一遍tarjan。可以求出一个点删除之后,增加的连通分量的数量(也就是成为割点的次数)。如果是根节点要记得减1
然后再取max就行了。

AC代码:

#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
#define sd(n) scanf("%d",&n)
#define sdd(n,m) scanf("%d%d",&n,&m)
#define sddd(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define pd(n) printf("%d\n", n)
#define pc(n) printf("%c", n)
#define pdd(n,m) printf("%d %d", n, m)
#define pld(n) printf("%lld\n", n)
#define pldd(n,m) printf("%lld %lld\n", n, m)
#define sld(n) scanf("%lld",&n)
#define sldd(n,m) scanf("%lld%lld",&n,&m)
#define slddd(n,m,k) scanf("%lld%lld%lld",&n,&m,&k)
#define sf(n) scanf("%lf",&n)
#define sc(n) scanf("%c",&n)
#define sff(n,m) scanf("%lf%lf",&n,&m)
#define sfff(n,m,k) scanf("%lf%lf%lf",&n,&m,&k)
#define ss(str) scanf("%s",str)
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
#define mem(a,n) memset(a, n, sizeof(a))
#define debug(x) cout << #x << ": " << x << endl
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mod(x) ((x)%MOD)
#define gcd(a,b) __gcd(a,b)
#define lowbit(x) (x&-x)
#define pii map<int,int>
#define mk make_pair
#define rtl rt<<1
#define rtr rt<<1|1
#define Max(x,y) (x)>(y)?(x):(y)
#define int long long

typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int MOD = 1e9 + 7;
const ll mod = 998244353;
const double eps = 1e-9;
const ll INF = 0x3f3f3f3f3f3f3f3fll;
//const int inf = 0x3f3f3f3f;
inline int read(){int ret = 0, sgn = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')sgn = -1;ch = getchar();}
while (ch >= '0' && ch <= '9'){ret = ret*10 + ch - '0';ch = getchar();}
return ret*sgn;}
inline void Out(int a){if(a>9) Out(a/10);putchar(a%10+'0');}
int qpow(int m, int k, int mod){int res=1,t=m;while(k){if(k&1)res=res*t%mod;t=t*t%mod;k>>=1;}return res;}
ll gcd(ll a,ll b){return b==0?a : gcd(b,a%b);}
ll lcm(ll a,ll b){return a*b/gcd(a,b);}
ll inv(ll x,ll m){return qpow(x,m-2,m)%m;}

const int N = 5e3+15;
vector<int> G[N];
int dfn[N],low[N],cnt[N];
int n,m;
int clk = 0;

void tarjan(int pos,int par,int del)
{
    dfn[pos] = low[pos] = ++clk;
    int nn = G[pos].size();
    for(int i = 0 ; i < nn ; i ++)
    {
        int to = G[pos][i];
        if(to == par || to == del) continue;
        if(!dfn[to])
        {
            tarjan(to,pos,del);
            low[pos] = min(low[pos],low[to]);
            // 割点的判断 记录成为割点的次数,也就是删除后连通分量的个数(或者说是子树的个数)
            if(low[to] >= dfn[pos])
                cnt[pos]++;
        }
        else
            low[pos] = min(low[pos],dfn[to]);
    }
}

signed main()
{
    while(~scanf("%lld%lld",&n,&m)){
    for(int i = 0 ; i < n ; i ++)
        G[i].clear();
    for(int i = 0 ; i < m ; i ++)
    {
        int x,y;
        scanf("%lld%lld",&x,&y);
        G[x].pb(y);
        G[y].pb(x);
    }
    int ans = 0;
    for(int i = 0 ; i < n ; i ++)
    {
        memset(dfn,0,sizeof(dfn));
        clk = 0;
        for(int j = 0 ; j < n ; j ++) cnt[j] = 1;
        int sum = 0;
        for(int j = 0 ; j < n ; j ++)
        {
            if(i != j && !dfn[j])
            {
                sum ++;                 // 跑一遍就说明这也是一个连通分量 所以sum++
                cnt[j] = 0;             // 根节点 cnt 要减一 因为已经是根节点了,不会因为删掉而影响父结点的连通性(因为没有父亲节点),那么只要求子树就可以了。而如果不是 那么删掉就会影响父亲节点的连通性。
                tarjan(j,-1,i);
            }
        }
        for(int j = 0 ; j < n ; j ++)
            if(i!=j)
                ans = max(ans,sum+cnt[j]-1);
    }
    printf("%lld\n",ans);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值