洛谷-跑步-NOI导刊2010提高

本文介绍了一个算法问题,如何找出从A点到B点路径中所有必经的路口。通过模拟删除除起点和终点外的每个点,判断是否仍能到达终点来确定必经点。使用了深度优先搜索(DFS)策略,实现了一种有效的方法来识别这些关键路口。
摘要由CSDN通过智能技术生成

新牛到部队, CG 要求它们每天早上搞晨跑,从A农场跑到B农场。从A农场到B农场中有n-2个路口,分别标上号,A农场为1号, B农场为n号,路口分别为 2 ..n -1 号,从A农场到B农场有很多条路径可以到达,而CG发现有的路口是必须经过的,即每条路径都经过的路口,CG要把它们记录下来,这样CG就可以先到那个路口,观察新牛们有没有偷懒,而你的任务就是找出所有必经路口。

输入输出格式

输入格式:

第一行两个用空格隔开的整数 n ( 3<=n<=2000 )和e ( 1<=e<= 8000 )。

接下来从第2到第e + 1行,每行两个用空格隔开的整数p和q,表示路口p和q之间有路径直达。

输入数据保证必经路口一定存在,并且每个路口都和A农场、B农场相连通。

输出格式:

第一行一个整数m,表示必经路口的数目。

第二行按从小到大的顺序依次输出每个必经路口的编号,每两个数之间用一个空格隔开。

输入输出样例

输入样例#1: 
6 6
1 2
2 4
2 3
3 5
4 5
5 6
输出样例#1: 
2
2 5


思路:就按照题目中的样子来模拟就好。
把除了起点和终点以外的所有点都试着删除一下,看看能否走到终点,如果能走到,则这个点一定不是必经点,反之则是必经点。

代码如下:
 1 #include <stdio.h>
 2 int cnt=0;
 3 int head[20000]={0};//表头数组 
 4 int flag=0;//1表示能走到终点,0表示不能
 5 int ans[20002]={0};//记录答案数组 
 6 int n,e;//点、边 
 7 int temp[20002]={0};//离线记录需要删除的点 
 8 struct Edge//领接表存储类型 
 9 {
10     int next,to;
11 }edge[16002];//一定要大点!!应该是边数的两倍多一点!!
12 
13 void add(int x,int y)//添加边
14 {
15     cnt++;
16     edge[cnt].next=head[x];
17     edge[cnt].to=y;
18     head[x]=cnt;
19 }
20 
21 void dfs(int start,int del)
22 {
23     if(start==n)//搜到了终点,不是必经点 
24     {
25         flag=1;
26         return ;
27     }
28     temp[start]=del;//离线记录需要删除的点 
29     for(int i=head[start];i!=0;i=edge[i].next)//从start开始,每次搜索start所连接的点 
30     {
31         int y=edge[i].to;//start所连接的点
32         if(temp[y]!=del&&y!=del) dfs(y,del);//如果走到的店点不是暂时删除的点,往下搜索,更新start为y 
33     }
34 }
35 
36 int main()
37 {
38     int p,q;
39     int i;
40     int ans[20002]={0};//记录答案
41     scanf("%d%d",&n,&e);
42     for(i=1;i<=e;i++)//添加无向图 
43     {
44         scanf("%d%d",&p,&q);
45         add(p,q);
46         add(q,p);
47     }
48     cnt=0;//记录答案数目
49     for(i=2;i<n;i++)
50     {
51         flag=0;
52         dfs(1,i);//从1号节点开始跑,依次删除编号为i的节点 
53         if(flag==0)//如果i是必经点 
54         {
55             cnt++;
56             ans[cnt]=i;
57         } 
58     }
59     /*============================*///输出答案 
60     printf("%d\n",cnt);
61     for(i=1;i<=cnt;i++)
62     {
63         printf("%d ",ans[i]);
64     }
65     printf("\n");
66     /*============================*///输出答案 
67     return 0;
68 }

 

 

转载于:https://www.cnblogs.com/geek-007/p/9929433.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值