图论——割点

poj1523
题目要求主要分两点:

1.找出图中的割点
2.计算出删除该割点及与该点相连的所有边后图中的 连通分量 数目

第一点容易计算,至于第二点,步骤如下:

1.定义数组vis[]来记录每个点的是否被访问,全部初始为0。
2.将割点对应的vis[]设为1,即将它视为已访问过。
3.从割点出发,枚举割点的所有边,对每条边进行一次dfs,dfs过程中遇到的点都将其vis[]设为1。
4.在 2 中遍历割点所有边的时候,如果该边所对应的点的vis[]为1,即该点已被扫描过,不可能是新的连通分量。只有当该边对应的点的vis[]为0才说明连通分量 +1!

代码如下:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define V  1005
int n,r;
using namespace std;
vector<int> vec[V];//存储边
int DFN[V],low[V];//dfn[u]表示结点u在树中的编号,low[u]表示在树中从u点出发,经过一条其后代组成的路径和回退边,所能到达的最小深度的顶点标号
int Times;
int Data_num = 0;
int roots;//根结点的孩子数
bool vis[V];
int all_v,subnets_num;//顶点个数,连通分量个数
vector<int>  cut_point;//存储找到的割点
void Init() {
    for(int i = 0; i0;
    roots = 0;
    all_v = 0;
    subnets_num = 0;
    cut_point.clear();
    memset(degree,0,sizeof(degree));
    memset(DFN,0,sizeof(DFN));
    memset(low,0,sizeof(low));
    memset(vis,0,sizeof(vis));
}

void tarjan(int s, int f) {
    DFN[s] = low[s] = ++Times;
    vector<int>::iterator pv;
    for (pv = vec[s].begin(); pv != vec[s].end(); ++pv) {
        if(*pv != f && DFN[*pv]if(DFN[*pv] == 0) {
                tarjan(*pv,s);
                low[s] = min(low[s],low[*pv]);
                if(DFN[s]<=low[*pv] && s!=1) {
                    bool is_add = true;//判断该点是否已经被存储了
                    for(int temp_i =0; temp_iif(cut_point[temp_i] == s)
                            is_add = false;
                    }
                    if(is_add)//若该点未被存储
                        cut_point.push_back(s);
                } else if(s == 1)
                    roots++;
            } else {
                low[s] = min(low[s],DFN[*pv]);
            }
        }
    }
    return;

}

void dfs(int start) {
    for(int finish = 0; finishif(!vis[vec[start][finish]]) {
            vis[vec[start][finish]] = 1;
            dfs(vec[start][finish]);
        }
    }
}




int main() {
    int flag = 0;//若连续两次出现0,则跳出全部循环
    while(1) {
        Init();
        while(1) {
            cin>>n;
            if(n==0) {
                flag++;
                break;
            }
            cin>>r;
            all_v++;
            flag = 0;
            vec[n].push_back(r);
            vec[r].push_back(n);
        }
        if(flag == 2)
            break;
        Data_num++;
        tarjan(1,-1);
        if(roots > 1) //树的孩子大于1
            cut_point.push_back(1);
        if(cut_point.size()<=0) {
            cout<<"Network #"<cout<<"  No SPF nodes"<continue;

        }
        cout<<"Network #"<int j = cut_point.size();
        for(; j>0; j--) {
            vis[cut_point[j-1]] = 1;
            subnets_num = 0;
            for(int i = 0; i1]].size(); i++) {
                if(!vis[vec[cut_point[j-1]][i]]) {
                    vis[vec[cut_point[j-1]][i]] = 1;
                    dfs(vec[cut_point[j-1]][i]);
                    subnets_num++;
                }
            }

            cout<<"  SPF node "<1]<<" leaves "<" subnets"<memset(vis,0,sizeof(vis));
        }
        cout<return 0;
}

ps:
该题尤其注意输出格式,同时,割点必须按照从小到大的顺序排列;
输出是否有 SPF 时句首要留两个空格;
每组数据输出结果后留一行空行

在这附上讨论区里某位大牛贴出的测试数据

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

1 2
2 3
3 4
4 5
5 1
0

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

1 2
0

1000 999
999 998
998 997
997 1000
0

1 2
2 3
0

1 2
1 3
1 4
1 5
0

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

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

0

以下是输出结果:

Network #1
SPF node 3 leaves 2 subnets

Network #2
No SPF nodes

Network #3
SPF node 2 leaves 2 subnets
SPF node 3 leaves 2 subnets

Network #4
No SPF nodes

Network #5
No SPF nodes

Network #6
SPF node 2 leaves 2 subnets

Network #7
SPF node 1 leaves 4 subnets

Network #8
SPF node 1 leaves 2 subnets
SPF node 2 leaves 3 subnets
SPF node 3 leaves 2 subnets

Network #9
No SPF nodes

good luck !

如有错误,还望指出!
转载请注明出处:http://blog.csdn.net/big_heart_c

你可能感兴趣的:(算法)