Kingpin Escape (BAPC 2018--K)

**

Kingpin Escape (BAPC 2018–K)

**

Description

You are the kingpin of a large network of criminal hackers.
Legend has it there has never been a richer criminal
than you. Not just because you are the smartest, but also
because you are the stingiest.
The police have been after you for years, but they have
never been able to catch you thanks to your great set
of escape routes. Whenever they want to catch you in
one of your many hideouts, you quickly get away through
your network of tunnels, back-alleys and speakeasies. Your
routes are set up so that from every hideout you have in the city you can get to any other
hideout by following only your secret passageways. Furthermore, because you are such a
penny-pincher, your network is the smallest possible: from every hideout to every other hideout
there is precisely one route through the network, no more and no fewer.
Yesterday, your mole in the police force has informed you of an unfortunate fact: the police
are on to you! They have gotten wind of your secret network, and will attempt to catch you.
They are planning to block some of your escape routes, and catch you in the act. They will
start blocking your secret passageways one by one, until you have nowhere left to go.
Fortunately, your headquarters are absolutely safe. If you can just get there, you are always
fine. Furthermore, your mole in the police force can inform you immediately as soon as the
police start blocking passageways, so that they only have time to block one of them before
you get notified. If you get back to your headquarters before they block any more routes,
you’re safe.
You want to add some passageways to the network so that whenever at most one of them is
blocked, you can still get to your headquarters from any other hideout. Since the news has
not changed your frugality, you want to extend your network as cheaply as possible. Can you
figure out the least number of passageways you need to add, and which ones you need?
Input
• The input starts with two integers 2 ≤ n ≤ 105
, the number of hideouts in the network,
and 0 ≤ h < n, the location of your headquarters.
• Then follow n − 1 lines, each with two integers 0 ≤ a, b < n, signifying that there is an
escape route between location a and location b.
Output
The output consists of:
• An integer m, the least number of escape routes you need to add to make the network
safe again.
22 Problem K: Kingpin Escape
• Then, m lines with two integers 0 ≤ a, b < n each, the hideouts between which one of
the escape routes has to be added.
In case there are multiple solutions, any of them will be accepted.
Sample Input 1 Sample Output 1
4 0
0 1
0 2
0 3
2
3 2
3 1
Sample Input 2 Sample Output 2
6 0
0 1
0 2
0 3
1 4
1 5
2
3 5
2 4

思路

一开始以为是找一条哈密尔顿回路,后面被教育了才知道是通过加边让一个树变成双连通图可,嗯,很简单。想了半个小时的题目用了四小时实现,嗯。。。。。。。

怎样让一棵树变成双连通图,即不存在割边?添加边
怎么添加边最好呢?在叶节点上添加

为什么在叶节点上添加是最好的呢?
赛后我仔细想了一下:

对于一个树,在任意两个节点上添加一条边都可以在这个加边后的树上找到一条经过这两个点的回路(图论定理)。那么对于一棵有根树,如果我们在根的两棵子树上,选取叶节点,那么就必可以找到一条经过这两个节点同时又经过根的回路,那么我们在不同子树上选取叶子连边就好啦。

原理是这样,其实实现的过程中,根本不需要考虑不同子树的问题,假如你选取的根的两棵子树的叶子数量一个为100,一个为8.按上述原理至少要添加100条边。其实如果是这种情况的话,完全可以换一个根,使得这个树的不同子树叶子数量变得可以两两配合(仔细想想,很简单),最多也是只有一个叶子配了两条边。所以我们的程序只需要数出叶子的数量

然后就是叶子节点配对的问题,由于我们是dfs搜的叶节点,那么对于一个叶子数量为k的树来说,我们找到的第i个节点跟第i+k/2个节点必是不同子树的(这个需要自己画图理解一下,如果发现不是,一定是你根选的不对),然后如果k是奇数,那么让第1个和第k个节点配对即可。

代码

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
#define maxn 100005
int root;
struct Edge{
    int to, next;
}edge[maxn*2];
int cnt, head[maxn];
int vis[maxn], leaf[maxn],cur = 0;
void add_edge(int u, int v){
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}

void dfs(int now, int fa){
    int i, j, k;
    if(vis[now]==1) leaf[++cur] = now;
    for(i = head[now]; i != -1; i = edge[i].next){
        int v = edge[i].to;
        if(v==fa){
            continue;
        }
        dfs(v, now);
    }
}

int main(){
    int i, j, k, n, m;
    scanf("%d %d",&n, &root);
    memset(head, -1, sizeof(head));
    for(i = 1; i < n; i++){
        scanf("%d%d",&j, &k);
        add_edge(j,k); 
        add_edge(k,j);
        vis[j]++;
        vis[k]++;
    }
    dfs(root, -1);
    printf("%d\n",(cur+1)/2);
    for(i = 1; i <= cur/2; i++){
        printf("%d %d\n",leaf[i],leaf[i+cur/2]);
    }
    if(cur%2) printf("%d %d\n",leaf[cur], leaf[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值