CodeForces 25D Roads not only in Berland

Description
Berland Government decided to improve relations with neighboring countries. First of all, it was decided to build new roads so that from each city of Berland and neighboring countries it became possible to reach all the others. There are n cities in Berland and neighboring countries in total and exactly n - 1 two-way roads. Because of the recent financial crisis, the Berland Government is strongly pressed for money, so to build a new road it has to close some of the existing ones. Every day it is possible to close one existing road and immediately build a new one. Your task is to determine how many days would be needed to rebuild roads so that from each city it became possible to reach all the others, and to draw a plan of closure of old roads and building of new ones.

Input
The first line contains integer n (2 ≤ n ≤ 1000) — amount of cities in Berland and neighboring countries. Next n - 1 lines contain the description of roads. Each road is described by two space-separated integers ai, bi (1 ≤ ai, bi ≤ n, ai ≠ bi) — pair of cities, which the road connects. It can’t be more than one road between a pair of cities. No road connects the city with itself.

Output
Output the answer, number t — what is the least amount of days needed to rebuild roads so that from each city it became possible to reach all the others. Then output t lines — the plan of closure of old roads and building of new ones. Each line should describe one day in the format i j u v — it means that road between cities i and j became closed and a new road between cities u and v is built. Cities are numbered from 1. If the answer is not unique, output any.

Sample Input
Input
2
1 2
Output
0
Input
7
1 2
2 3
3 1
4 5
5 6
6 7
Output
1
3 1 3 7

思路:
首先什么样的边需要拆掉呢?
加入到集合中会产生环的边。
怎么样会产生环?
用并查集就是如果把两个父节点相同的点连在一起就会产生环。

用并查集做。记录每个节点的父节点,如果在建树阶段对于两个要放进统一集合的点其父节点已经相同,那么说明如果将这两个节点连在一起的话将会产生环,即这两个节点没有必要连在一起,也就是要拆掉的边。
什么样的边需要连在一起?
在并查集中,我们只需要用边从两个集合中分别选取一个点,将这两个点连在一起即可。至于选取哪个点,当然是集合中的根节点最方便,也就是自身就是自己的父节点的点。

#include <cstdio>
using namespace std;
int pre[1090];
int chai[1090];
int jian[1090];
int u[1090],v[1090];
int n;
int fin(int f)
{
    return f==pre[f]?f:pre[f]=fin(pre[f]);
}
int main()
{
    scanf("%d",&n);
    int uu,vv;
    for(int i=1;i<=n;i++)
        pre[i]=i;
    int cnt=0;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&u[i],&v[i]);
        uu=fin(u[i]);
        vv=fin(v[i]);
        if(uu==vv)//说明这条边需要拆掉
            chai[++cnt]=i;
        else pre[uu]=vv;
    }
    int ii=0;
    for(int i=1;i<=n;i++)
    {
        if(pre[i]==i)//集合中的根节点
            jian[++ii]=i;
    }
    printf("%d\n",cnt);
    for(int i=1;i<=cnt;i++)
    {
        printf("%d %d %d %d\n",u[chai[i]],v[chai[i]],jian[i],jian[i+1]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值