poj3694 Network

本文介绍了一位网络管理员如何管理大型网络,网络由N台计算机和M条链接组成。管理员发现某些链接对网络至关重要,因为任何一条链接的故障都可能导致数据无法在某些计算机之间传输。这些关键链接被称为桥梁。管理员计划逐步添加新的链接以消除所有桥梁。题目要求在每次添加新链接后报告网络中的桥梁数量。文章提供了输入输出示例,并讨论了利用最近公共祖先(LCA)和深度优先搜索(DFS)来解决此问题的思路。
摘要由CSDN通过智能技术生成

Network
Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 9386 Accepted: 3496

Description

A network administrator manages a large network. The network consists of N computers and M links between pairs of computers. Any pair of computers are connected directly or indirectly by successive links, so data can be transformed between any two computers. The administrator finds that some links are vital to the network, because failure of any one of them can cause that data can't be transformed between some computers. He call such a link a bridge. He is planning to add some new links one by one to eliminate all bridges.

You are to help the administrator by reporting the number of bridges in the network after each new link is added.

Input

The input consists of multiple test cases. Each test case starts with a line containing two integers N(1 ≤ N ≤ 100,000) and M(N - 1 ≤ M ≤ 200,000).
Each of the following M lines contains two integers A and B ( 1≤ A ≠ B ≤ N), which indicates a link between computer A and B. Computers are numbered from 1 to N. It is guaranteed that any two computers are connected in the initial network.
The next line contains a single integer Q ( 1 ≤ Q ≤ 1,000), which is the number of new links the administrator plans to add to the network one by one.
The i-th line of the following Q lines contains two integer A and B (1 ≤ A ≠ B ≤ N), which is the i-th added new link connecting computer A and B.

The last test case is followed by a line containing two zeros.

Output

For each test case, print a line containing the test case number( beginning with 1) and Q lines, the i-th of which contains a integer indicating the number of bridges in the network after the first i new links are added. Print a blank line after the output for each test case.

Sample Input

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

Sample Output

Case 1:
1
0

Case 2:
2
0

今天做了训练计划中双联通分量的第二题,算是又一步深刻理解了LCA和深搜函数的运用,不得不说大白书上写的深搜函数要比很多博客上要好用的多,效率高也比较简单,深搜函数最终要的作用就是可以给点建立一棵深搜树,然后根据时间戳就可以判断找到割顶和桥(割边)了。

然后说一说这个题:

大意:

给你n个点和m条边,然后会有q次添加边,问你添加上当前边之后,剩下的桥的个数是多少。

思路:

对于每条添加的边(u,v),设u,v的最近公共祖先是c,那么桥数就会减少u~c的路径上的桥数+v~c的路径上的桥数,读者可以自己画图想一想为什么会是这样的。

这样我们就可以深搜一次的过程中找出桥,顺便记录搜索时每个结点的祖先。

具体的找最近公共祖先以及在路径上找桥的函数看代码吧。


另外在别的博客上看到的这个函数一直都搞不懂,因为觉得那根本是错的,然而却都能A掉这道题......不知道数据有多水。

当然我这个是按照自己画图得来的,也能A掉。。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
using namespace std;
const int MAXN=100000+5;

int n,m;
bool bridge[MAXN];
int pre[MAXN],dfn[MAXN];
int dfs_colock,bcc_cnt;

typedef vector<int>ve;//黑科技ヾ(o◕∀◕)ノヾ效率会变高,会变得多高呢自己试试吧
vector<ve>G(MAXN);

int dfs(int u,int fa)
{
    int lowu=dfn[u]=++dfs_colock;
    for(int i=0,l=G[u].size(); i<l; ++i)
    {
        int v=G[u][i];
        if(!dfn[v])
        {
            int lowv=dfs(v,u);
            pre[v]=u;
            lowu=min(lowu,lowv);
            if(lowv>dfn[u])
            {
                bcc_cnt++;
                bridge[v]=1;
            }
        }
        else if(dfn[u]>dfn[v]&&v!=fa)
        {
            lowu=min(lowu,dfn[v]);
        }
    }
    return lowu;
}
void find_bcc()
{
    int i;
    for(i=0; i<n; ++i)
    {
        pre[i]=i;
        dfn[i]=0;
        bridge[i]=0;
    }
    bcc_cnt=dfs_colock=0;
    dfs(0,-1);
}
int judge(int u,int v)
{
    int sum=0;
    while(u!=v)
    {
        while(dfn[u]>dfn[v])
        {
            if(bridge[u])
            {
                sum++;
                bridge[u]=0;
            }
            u=pre[u];
        }
        while(dfn[v]>dfn[u])
        {
            if(bridge[v])
            {
                sum++;
                bridge[v]=0;
            }
            v=pre[v];
        }
    }
    return sum;
}

int main()
{
    int i,ca=0;
    while(~scanf("%d%d",&n,&m))
    {
        if(!n&&!m)break;
        ca++;
        for(i=0; i<n; ++i)
        {
            G[i].clear();
        }
        int u,v,q;
        while(m--)
        {
            scanf("%d%d",&u,&v);
            u--;
            v--;
            G[u].push_back(v);
            G[v].push_back(u);
        }
        find_bcc();
        scanf("%d",&q);
        printf("Case %d:\n",ca);
        while(q--)
        {
            scanf("%d%d",&u,&v);
            u--;
            v--;
            bcc_cnt-=judge(u,v);
            printf("%d\n",bcc_cnt);
        }
        puts("");
    }
    return 0;
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值