G - Railway HDU - 3394(点双连通分量)

There are some locations in a park, and some of them are connected by roads. The park manger needs to build some railways along the roads, and he would like to arrange tourist routes to each circuit. If a railway belongs to more than one tourist routes, there might be clash on it, and if a railway belongs to none tourist route, it doesn’t need to build. 
Now we know the plan, and can you tell us how many railways are no need to build and how many railways where clash might happen.

Input

The Input consists of multiple test cases. The first line of each test case contains two integers, n (0 < n <= 10000), m (0 <= m <= 100000), which are the number of locations and the number of the railways. The next m lines, each line contains two integers, u, v (0 <= u, v < n), which means the manger plans to build a railway on the road between u and v. 
You can assume that there is no loop and no multiple edges. 
The last test case is followed by two zeros on a single line, which means the end of the input.

Output

Output the number of railways that are no need to build, and the number of railways where clash might happen. Please follow the format as the sample.

Sample Input

8 10
0 1
1 2
2 3
3 0
3 4
4 5
5 6
6 7
7 4
5 7
0 0

Sample Output

1 5

题目大意:给出n个点m条边的无向图简单图(无环无重边),每一个环会安排一条旅游路线,如果一条边不属于任何路线(环),就认为是没有必要的;如果一条边属于多条旅游路线,则认为是会冲突的;求出没必要的边和冲突边数

 

题解:

  • 没必要边很简单,就是桥,不属于任何环;冲突边一开始读错题了,以为安排旅游路线的环必须是尽可能大的,结果跑去求边双连通了。其实应该求点双连通
  • 至于冲突边,可以发现,如果一个k个点的环,应该有k条边,若超出k条边,则它肯定不止一个环,这样这个环里每条边都是冲突边了(环里的每一条边属于不止一个环)。
  • 因此,求出桥的数量,再求出有多少个点双分量的点数小于边数的,把边数相加即可

代码:还是应该加强一下点双和边双的求法以及和割点割边之间的联系

//#include<bits/stdc++.h>
#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<map>
#include<stack>
#include<vector>
#define rep(i,e) for(int i=0;i<(e);++i)
#define rep1(i,e) for(int i=1;i<=(e);++i)
#define repx(i,x,e) for(int i=(x);i<=(e);++i)
#define pii pair<int,int>
#define X first
#define Y second
#define PB push_back
#define MP make_pair
#define mset(var,val) memset(var,val,sizeof(var))
#define scd(a) scanf("%d",&a)
#define scdd(a,b) scanf("%d%d",&a,&b)
#define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define IOS ios::sync_with_stdio(false);cin.tie(0)

using namespace std;

#ifdef LOCAL
template<typename T>
void dbg(T t){
    cout<<t<<" "<<endl;
}
template<typename T, typename... Args>
void dbg(T t, Args... args){
    cout<<t<<" ";dbg(args...);
}


#else
#define dbg(...)
#endif // local
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fll;
const int mod = 1e9+7;
const int N = 500+10;
typedef long long ll;
const int maxn = 1e4+10;
const int maxm =1e5+10;

struct node{
    int u,v,next;
}edge[maxm*2];
int head[maxn],low[maxn],dfn[maxn],dfn_cnt,bccno[maxn],bcc_cnt;
int cnt,iscut[maxm*2],cut_cnt;
bool vis[maxn];
int bcce[maxn];
stack<pii>S;
vector<int>B[maxn];
void add(int u,int v)
{
    edge[++cnt].v = v;
    edge[cnt].u = u;
    edge[cnt].next = head[u];
    head[u] = cnt;
}

void tarjan(int u,int fa)
{
    low[u] = dfn[u] = ++dfn_cnt;
    for(int i = head[u]; ~i; i = edge[i].next)
    {
        int v = edge[i].v;
        pii p = MP(u,v);
        if(!dfn[v])
        {
            S.push(p);
            tarjan(v,u);
            low[u] = min(low[u],low[v]);
            if(low[v] > dfn[u])
                cut_cnt++;
            if(low[v] >= dfn[u])
            {
                bcc_cnt++;
                B[bcc_cnt].clear();
                for(;;){
                    bcce[bcc_cnt]++;
                    pii tmp = S.top();S.pop();
                    if(bccno[tmp.X] != bcc_cnt) B[bcc_cnt].PB(tmp.X),bccno[tmp.X] = bcc_cnt;
                    if(bccno[tmp.Y] != bcc_cnt) B[bcc_cnt].PB(tmp.Y),bccno[tmp.Y] = bcc_cnt;
                    if(tmp.X == u && tmp.Y == v) break;
                }
            }
        }else if(dfn[v] < dfn[u] && v != fa)
        {
            S.push(p);
            low[u] = min(low[u],dfn[v]);
        }
    }
}


void work()
{
    int n,m,x,y;
    while(cin>>n>>m)
    {
        for(int i = 0; i <= n; i++)
        {
            head[i] = -1;
            low[i] = dfn[i] = bccno[i] = vis[i] = bcce[i]  = 0;
        }
        bcc_cnt = cut_cnt = 0;
        cnt = 1;
        dfn_cnt = 0;
        memset(iscut,0,sizeof(iscut));
        if(n == m && n == 0) break;
        for(int i = 0; i < m; i++)
        {
            cin>>x>>y;
            add(x,y);
            add(y,x);
        }
        for(int i = 0; i < n; i++)
        {
            if(!dfn[i])
                tarjan(i,-1);
        }
        cout<<cut_cnt<<" ";
        int res = 0;
        for(int i = 1; i <= bcc_cnt; i++)
        {
            if(bcce[i] > B[i].size())
                res += bcce[i];
        }
        cout<<res<<endl;
    }
}

int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    IOS;
    work();
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值