P1656 炸铁路

题目描述

A 国派出将军uim,对 B 国进行战略性措施,以解救涂炭的生灵。

B 国有 nn 个城市,这些城市以铁路相连。任意两个城市都可以通过铁路直接或者间接到达。

uim 发现有些铁路被毁坏之后,某两个城市无法互相通过铁路到达。这样的铁路就被称为 key road。

uim 为了尽快使该国的物流系统瘫痪,希望炸毁铁路,以达到存在某两个城市无法互相通过铁路到达的效果。

然而,只有一发炮弹(A 国国会不给钱了)。所以,他能轰炸哪一条铁路呢?

输入格式

第一行 nn,m (1 \leq n\leq 150m(1≤n≤150,1 \leq m \leq 5000)1≤m≤5000),分别表示有 nn 个城市,总共 mm 条铁路。

以下 mm 行,每行两个整数 a, ba,b,表示城市 aa 和城市 bb 之间有铁路直接连接。

输出格式

输出有若干行。

每行包含两个数字 aa,bb,其中 a<ba<b,表示 <a,b><a,b> 是 key road。

请注意:输出时,所有的数对 <a,b><a,b> 必须按照 aa 从小到大排序输出;如果aa 相同,则根据 bb 从小到大排序。

输入输出样例

输入 #1复制

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

输出 #1复制

1 2
5 6

这道题考查的是图的割边

图的割边与割点步骤几乎一致,代码实现中只有一个等于号的区别

关于图的割点割边问题我写在了这篇博客里

(还没写 等我写了之后再来贴链接)

此题算是一个典型的图的割边模板问题,思路是:深度优先遍历每一个点,深度优先遍历到点u时,假设图中还有顶点v是没有访问过的点,判断顶点v能否回到之前访问过的点(包括点u),判断方法是:对顶点v再进行一次深度优先遍历,但是此次遍历不允许经过顶点u,倘若顶点v不能回到祖先,也没有另外一条路能回到u,那么u-v这条边就是割边。

这道题还有一个特别之处就是输出时,所有的数对 <a,b> 必须按照 a 从小到大排序输出;如果a 相同,则根据 b 从小到大排序。就需要对割边用结构体数组进行存储,然后按照该规则进行排序。

ac代码

#include<bits/stdc++.h>
using namespace std;
#define N 160
int n,m,x,y;
int v[N][N];
int num[N],low[N],flag[N],dex,o;
struct
{
    int x,y;
} ans[N];

void dfs(int cur,int father)
{
    dex++;
    num[cur]=dex;
    low[cur]=dex;
    for(int i=1; i<=n; i++)
    {
        if(v[cur][i] == 1)
        {
            if(num[i] == 0)
            {
                dfs(i,cur);
                low[cur]=min(low[i],low[cur]);
                if(low[i]>num[cur])
                {
                    ans[o].x=cur;
                    ans[o].y=i;
                    o++;
                }
            }
            else if(i != father)
            {
                low[cur]=min(low[cur],num[i]);
            }
        }
    }
}
int main()
{

    cin>>n>>m;
    while(m--)
    {
        cin>>x>>y;
        v[x][y]=1;
        v[y][x]=1;
    }
    int root=1;
    dfs(1,root);
    
    ///排序
    for(int i=0; i<o-1; i++)
        for(int j=i+1; j<o; j++)
           {
              if(ans[j].x<ans[i].x)
                {
                   int temp=ans[j].x;ans[j].x=ans[i].x;ans[i].x=temp;
                       temp=ans[j].y;ans[j].y=ans[i].y;ans[i].y=temp;
                }
              else if(ans[j].x == ans[i].x)
                     {
                        if(ans[j].y<ans[i].y)
                        {
                           int temp=ans[j].x;ans[j].x=ans[i].x;ans[i].x=temp;
                           temp=ans[j].y;ans[j].y=ans[i].y;ans[i].y=temp;
                         }
                      }
           }
    for(int i=0; i<o; i++)
        cout<<ans[i].x<<" "<<ans[i].y<<endl;
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值