poj1523
题目要求主要分两点:
1.找出图中的割点
2.计算出删除该割点及与该点相连的所有边后图中的 连通分量 数目
第一点容易计算,至于第二点,步骤如下:
1.定义数组vis[]来记录每个点的是否被访问,全部初始为0。
2.将割点对应的vis[]设为1,即将它视为已访问过。
3.从割点出发,枚举割点的所有边,对每条边进行一次dfs,dfs过程中遇到的点都将其vis[]设为1。
4.在 2 中遍历割点所有边的时候,如果该边所对应的点的vis[]为1,即该点已被扫描过,不可能是新的连通分量。只有当该边对应的点的vis[]为0才说明连通分量 +1!
代码如下:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<fstream>
#include<vector>
#include<iostream>
#include<math.h>
#include<string>
#include<vector>
#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; i<V; i++)
vec[i].clear();
Times = 0;
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]<DFN[s]) {
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_i<cut_point.size(); temp_i++) {
if(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; finish<vec[start].size(); finish++) {
if(!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 #"<<Data_num<<endl;
cout<<" No SPF nodes"<<endl<<endl;
continue;
}
cout<<"Network #"<<Data_num<<endl;
int j = cut_point.size();
for(; j>0; j--) {
vis[cut_point[j-1]] = 1;
subnets_num = 0;
for(int i = 0; i<vec[cut_point[j-1]].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 "<<cut_point[j-1]<<" leaves "<<subnets_num<<" subnets"<<endl;
memset(vis,0,sizeof(vis));
}
cout<<endl;
}
return 0;
}
ps:
该题尤其注意输出格式,同时,割点必须按照从小到大的顺序排列;
输出是否有 SPF 时句首要留两个空格;
每组数据输出结果后留一行空行
在这附上讨论区里某位大牛贴出的测试数据
1 2
5 4
3 1
3 2
3 4
3 5
01 2
2 3
3 4
4 5
5 1
01 2
2 3
3 4
4 6
6 3
2 5
5 1
01 2
01000 999
999 998
998 997
997 1000
01 2
2 3
01 2
1 3
1 4
1 5
01 2
1 3
1 4
2 3
2 5
2 6
3 7
3 8
7 8
01 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5
00
以下是输出结果:
Network #1
SPF node 3 leaves 2 subnetsNetwork #2
No SPF nodesNetwork #3
SPF node 2 leaves 2 subnets
SPF node 3 leaves 2 subnetsNetwork #4
No SPF nodesNetwork #5
No SPF nodesNetwork #6
SPF node 2 leaves 2 subnetsNetwork #7
SPF node 1 leaves 4 subnetsNetwork #8
SPF node 1 leaves 2 subnets
SPF node 2 leaves 3 subnets
SPF node 3 leaves 2 subnetsNetwork #9
No SPF nodes
good luck !
如有错误,还望指出!
转载请注明出处:http://blog.csdn.net/big_heart_c