[题解]牛跑步

前言:

哈哈,今晚再写一篇题解

并查集双杀

题目描述

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

输入输出格式

输入格式:

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

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

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

输出格式:

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

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

注意:不包括起点和终点。

输入输出样例

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

 题目分析:

我们假如用并查集的思想,枚举 每一个节点,清空并查集,将 除该割点相关边所连点加入并查集,如果 1与n都在此并查集(1、n祖先为一个节点)证明 不需要这个割点也可以到达最后,那么这个点就不为 必经点。

上面的分析如果没有看懂一定要多看几次,再拿笔推一推,这道题就明了了。
 

代码:

 1 #include<iostream>
 2 #include<fstream>
 3 #include<cstring>
 4 using namespace std;
 5 
 6 const int Max_N=2e3+5;
 7 const int Max_E=1.6e4+5;
 8 
 9 int n,e,tot,cnt;
10 int Next[Max_E],root[Max_N],to[Max_E];
11 
12 int Fa[Max_N],res[Max_N];
13 
14 void Add_Edge(int u,int v)
15 {
16 //    链式前向星
17     Next[++tot]=root[u];
18     root[u]=tot;
19     to[tot]=v;
20     return ;
21 }
22 void init()
23 {
24 //     初始化并查集
25     register int i;
26     for(i=1;i<=n;i++)
27         Fa[i]=i;
28     return ;
29 }
30 int Find(int p)
31 {
32 //     查找节点祖先
33     if(Fa[p]==p)
34         return p;
35     return Fa[p]=Find(Fa[p]);
36 }
37 void megre(int l,int r)
38 {
39 //     合并两点
40     Fa[Find(l)]=Fa[Find(r)];
41     return ;
42 }
43 void Ge(int p)
44 {
45 //     枚举割点
46     register int i,j;
47     for(i=1;i<=n;i++)
48         if(i^p)
49             for(j=root[i];j^0;j=Next[j])
50                 if(to[j]^p)
51                     megre(i,to[j]);
52     return ;
53 }
54 int main()
55 {
56     scanf("%d%d",&n,&e);
57     register int i;
58     int x,y;
59     for(i=1;i<=e;i++){
60         scanf("%d%d",&x,&y);
61         Add_Edge(x,y);
62         Add_Edge(y,x);
63 //             此图为无向图
64     }
65     int Ans=0;
66     for(i=2;i<n;i++){
67         init();
68         Ge(i);
69         if(Find(1)^Find(n)){
70 //                     不需要该点依然合格
71             Ans++;
72             res[++cnt]=i;
73         }
74     }
75     printf("%d\n",Ans);
76     for(i=1;i<=cnt;i++){
77         if(i>1)
78             printf(" ");
79         printf("%d",res[i]);
80     }
81     return 0;
82 }
代码

 

写在最后的话:

题解仅供思路,要想成为 dalao ,请学会并尽量会做到教他人甚至自己写题解。

博主(目前)是一名初二蒟蒻,如有问题还请大家指出,一起交流学习!

Happy every day!        ——2019.4.11

 

转载于:https://www.cnblogs.com/lihepei/p/10691795.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
06-01
这道题是一道典型的费用限制最短路题目,可以使用 Dijkstra 算法或者 SPFA 算法来解决。 具体思路如下: 1. 首先,我们需要读入输入数据。输入数据中包含了道路的数量、起点和终点,以及每条道路的起点、终点、长度和限制费用。 2. 接着,我们需要使用邻接表或邻接矩阵来存储图的信息。对于每条道路,我们可以将其起点和终点作为一个有向边的起点和终点,长度作为边权,限制费用作为边权的上界。 3. 然后,我们可以使用 Dijkstra 算法或 SPFA 算法求解从起点到终点的最短路径。在这个过程中,我们需要记录到每个点的最小费用和最小长度,以及更新每条边的最小费用和最小长度。 4. 最后,我们输出从起点到终点的最短路径长度即可。 需要注意的是,在使用 Dijkstra 算法或 SPFA 算法时,需要对每个点的最小费用和最小长度进行松弛操作。具体来说,当我们从一个点 u 经过一条边 (u,v) 到达另一个点 v 时,如果新的费用和长度比原来的小,则需要更新到达 v 的最小费用和最小长度,并将 v 加入到优先队列(Dijkstra 算法)或队列(SPFA 算法)中。 此外,还需要注意处理边权为 0 或负数的情况,以及处理无法到达终点的情况。 代码实现可以参考以下样例代码: ```c++ #include <cstdio> #include <cstring> #include <queue> #include <vector> using namespace std; const int MAXN = 1005, MAXM = 20005, INF = 0x3f3f3f3f; int n, m, s, t, cnt; int head[MAXN], dis[MAXN], vis[MAXN]; struct Edge { int v, w, c, nxt; } e[MAXM]; void addEdge(int u, int v, int w, int c) { e[++cnt].v = v, e[cnt].w = w, e[cnt].c = c, e[cnt].nxt = head[u], head[u] = cnt; } void dijkstra() { priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q; memset(dis, 0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)); dis[s] = 0; q.push(make_pair(0, s)); while (!q.empty()) { int u = q.top().second; q.pop(); if (vis[u]) continue; vis[u] = 1; for (int i = head[u]; i != -1; i = e[i].nxt) { int v = e[i].v, w = e[i].w, c = e[i].c; if (dis[u] + w < dis[v] && c >= dis[u] + w) { dis[v] = dis[u] + w; q.push(make_pair(dis[v], v)); } } } } int main() { memset(head, -1, sizeof(head)); scanf("%d %d %d %d", &n, &m, &s, &t); for (int i = 1; i <= m; i++) { int u, v, w, c; scanf("%d %d %d %d", &u, &v, &w, &c); addEdge(u, v, w, c); addEdge(v, u, w, c); } dijkstra(); if (dis[t] == INF) printf("-1\n"); else printf("%d\n", dis[t]); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值