题意:
给定一个由箭头组成的赛道,箭头起始点有标号,运动员从0点出发,只能沿箭头方向跑,到下一点后,可选择任意箭头继续跑。
路线有以下特点:
1,每一点都能从出发点到达
2,每一点都可到达终点
3,终点无向外的箭头
运动员要到达终点,不要求经过路线上所有点。但路线上有些点为必经点。若比赛分两天进行,要把赛道分成完全分离的两部分,这两部分只有一个分裂点有重合。
一. 找到所有必经点
二. 找到所有分裂点
输入:
前n行,每行输入的数字为i点出发的箭头可到达的点,以-2结束
最后一行为-1,表示输入结束
输出:
第一行输出必经点个数和所有的必经点
第二行输出分裂点个数和所有的分裂点
先从路线中删除i点,用dfs搜索出发点可达位置,若不能到达终点,则i为必经点。若i为分裂点,则i必定为必经点。在找到一个必经点后,枚举所有起始点能到达的点和不能到达的点,判断这两类点间是否有边相连,若有边相连,则i不为分裂点。
1 #include<iostream>
2 #include<string.h>
3 using namespace std ;
4 int data[1000][1000], visited[1000], n ;
5 void bfs(int s){ //宽度优先搜索
6 int i, open, closed, queue[1000] ;
7 visited[s] = 0 ;
8 queue[1] = s ;
9 open = 1 ;
10 closed = 1 ;
11 while(open<=closed){
12 for(i=0; i<n; i++)
13 if(visited[i]==-1&&data[queue[open]][i]!=0){
14 visited[i] = visited[queue[open]] + 1 ;
15 closed ++ ;
16 queue[closed] = i ;
17 }
18 open ++ ;
19 }
20 }
21 int main(){
22 int data1[1000][1000], i, j, a[1000], b[1000], a1=0, b1=0 ;
23 cin >> n ;
24 for(i=1;; i++){ //读取完整路线
25 while(true){
26 cin >> j ;
27 if(j==-2) break ;
28 data1[i][j] = 1 ;
29 }
30 cin >> j ;
31 if(j==-1) break ;
32 data1[i+1][j] = 1 ;
33 }
34 memset(visited, -1, sizeof(visited)) ;
35 for(i=1; i<n; i++){
36 data = data1 ; //数组复制,直接简化了
37 for(j=1; j<=n; j++){
38 data[i][j] = 0 ;
39 data[j][i] = 0 ;
40 }
41 bfs(0) ; //搜索删除i点后顶点所能到达的位置
42 if(visited[n]==-1){ //若不能到达终点,则i为必经点
43 a[a1] = i ;
44 a1 ++ ;
45 bool fund = true ;
46 for(int k=0; k<n; k++)
47 for(int p=0; p<=n; p++){//若删除i后0可达的点和不可达的点间有交集,则i不为分裂点
48 if(visited[k]!=-1&&visited[p]==-1&&(data[k][p]!=0||data[p][k]!=0)){
49 fund = false ;
50 break ;
51 }
52 }
53 if(fund){
54 b[b1] = i ;
55 b1 ++ ;
56 }
57 }
58 }
59 cout << "必经点个数为: " << a1 << " 分别为:" ;
60 for(i=0; i<a1; i++)
61 cout << a[i] << " " ;
62 cout << endl ;
63 cout << "分裂点个数为:" << b1 << " 分别为:" ;
64 for(i=0; i<b1; i++)
65 cout << b[i] << " " ;
66 return 0 ;
67 }
2 #include<string.h>
3 using namespace std ;
4 int data[1000][1000], visited[1000], n ;
5 void bfs(int s){ //宽度优先搜索
6 int i, open, closed, queue[1000] ;
7 visited[s] = 0 ;
8 queue[1] = s ;
9 open = 1 ;
10 closed = 1 ;
11 while(open<=closed){
12 for(i=0; i<n; i++)
13 if(visited[i]==-1&&data[queue[open]][i]!=0){
14 visited[i] = visited[queue[open]] + 1 ;
15 closed ++ ;
16 queue[closed] = i ;
17 }
18 open ++ ;
19 }
20 }
21 int main(){
22 int data1[1000][1000], i, j, a[1000], b[1000], a1=0, b1=0 ;
23 cin >> n ;
24 for(i=1;; i++){ //读取完整路线
25 while(true){
26 cin >> j ;
27 if(j==-2) break ;
28 data1[i][j] = 1 ;
29 }
30 cin >> j ;
31 if(j==-1) break ;
32 data1[i+1][j] = 1 ;
33 }
34 memset(visited, -1, sizeof(visited)) ;
35 for(i=1; i<n; i++){
36 data = data1 ; //数组复制,直接简化了
37 for(j=1; j<=n; j++){
38 data[i][j] = 0 ;
39 data[j][i] = 0 ;
40 }
41 bfs(0) ; //搜索删除i点后顶点所能到达的位置
42 if(visited[n]==-1){ //若不能到达终点,则i为必经点
43 a[a1] = i ;
44 a1 ++ ;
45 bool fund = true ;
46 for(int k=0; k<n; k++)
47 for(int p=0; p<=n; p++){//若删除i后0可达的点和不可达的点间有交集,则i不为分裂点
48 if(visited[k]!=-1&&visited[p]==-1&&(data[k][p]!=0||data[p][k]!=0)){
49 fund = false ;
50 break ;
51 }
52 }
53 if(fund){
54 b[b1] = i ;
55 b1 ++ ;
56 }
57 }
58 }
59 cout << "必经点个数为: " << a1 << " 分别为:" ;
60 for(i=0; i<a1; i++)
61 cout << a[i] << " " ;
62 cout << endl ;
63 cout << "分裂点个数为:" << b1 << " 分别为:" ;
64 for(i=0; i<b1; i++)
65 cout << b[i] << " " ;
66 return 0 ;
67 }