ECNA2017 F-Keeping On Track【图的搜索】

本文探讨了在战争背景下,如何通过优化铁路网络结构来减少关键节点被破坏后的影响。通过对给定的无向图进行深度优先搜索,计算并找出在特定节点移除后,使图分裂成多个连通子图时,子图间断开连接的点对数量最大化的策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

Acmar and Ibmar are at war! You are in charge of a rail network that transports important supplies throughout the great state of Acmar during this delicate time. The rail system is made up of a set of rail lines which meet at various junction points. While there is no limit to the number of rail lines that can meet at a junction, the network is set up so that there is only one path between any two junctions. You’ve tried to argue for some redundancy in the system, i.e., extra rail lines so that there are two or more paths connecting some junctions, but it’s wartime and budgets are tight. However, this may soon change as you’ve just been given some terrible news from double agents working in Ibmar: within the next month enemy spies plan to blow up one of the junctions! Unfortunately, the exact junction is not known, but knowing your enemy well you are certain that they will undoubtedly strike the critical junction, specifically the junction whose removal disconnects the most pairs of other remaining junctions in the system. You don’t have much time to act, so the most you can do is add one new line connecting two currently unconnected junctions, thereby reducing the number of disconnected pairs after the critical junction has been destroyed. Your job is to determine how to make the number of disconnected pairs as small as possible by adding in the best possible rail line.

Input

Input starts with a line containing an integer n (2 ≤ n ≤ 10 000) indicating the number of rail lines in the system. Following that are n lines of the form i1 i2 indicating that a rail line connects junctions i1 and i2. Junctions are numbered consecutively starting at 0. All rail lines are two-way and no rail line appears more than once in the input. There is exactly one path between any two junction points given in the input.

Output

Display two values n1 and n2, where n1 is the number of pairs of junctions which will be disconnected when the enemy destroys the critical junction, and n2 is the number of pairs of junctions still disconnected after you add in the best possible rail line. There will never be more than one critical junction.

Sample Input

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

Sample Output 1

11 5

Sample Input 2

2
2 1
0 1

Sample Output

1 0

题意

给n条边组成的无向图,点的坐标从0~n,且每两个点都有且只有一条边,删除某一个点时,且删除和该点所连得边,使得这个图分成了若干连通图,每个连通图都有ki个点,求n1:任意两个ki相乘加和后所能得到的最大值,求n2:n1减去两个最大的ki相乘

思路

题意可能比较难理解,所以多读几遍题。遇到很多次图上搜索点的个数的问题都不太会,于是打算写一下这个题。

代码中dfs的意思是计算删除这个点时的n1值,dfs2是求删除这个点时,所的连通图点数最多的两个图的点的个数。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int Maxn = 10005;
const int Maxm = 20005;
int head[Maxn];
bool vis[Maxn];
int num, n1, n2, n, p, max1 = -1, max2 = -2;
struct edge{
    int to;
    int next;
};
edge e[Maxm];//注意建立双向边需要开两倍

void addedge(int from, int to)
{
    e[num].to = to;
    e[num].next = head[from];
    head[from] = num++;
}

int dfs(int s)  //搜索每个点删去后的n1值
{
    int t1 = 0,t = 0,ans = 0;
    vis[s] = true;
    for(int i = head[s]; i != -1; i = e[i].next)
    {
        int to = e[i].to;
        if(!vis[to])
        {
            t1 = dfs(to);//每次dfs表示删除该点后,其中一个连通图中点的个数
            t += t1;
            ans += t1 * (n - t1);
            //printf("%d %d %d\n", e[i].to, t1, ans);
        }
    }
    ans += t * (n - t);
    ans /= 2;
    //printf("%d %d\n", s, ans);
    if(ans>n1)
    {
        n1 = ans;
        p = s;
    }
    return t+1;
}

int dfs2(int s)
{
    int t = 0,t1 = 0;
    vis[s] = true;
    for(int i = head[s]; i != -1; i = e[i].next)
    {
        int to = e[i].to;
        if(!vis[to])
        {
            t1 = dfs2(to);
            t += t1;
            //if(s == p)
            //    printf("%d %d\n",s, t1);
            if(s == p && t1 > max1)
            {
                max2 = max1;
                max1 = t1;
                continue;
            }
            if(s == p && t1 <= max1 && t1 > max2)
                max2 = t1;
        }
    }
    return t+1;
}
int main()
{
    int a,b;
    num = 0;
    memset(head, -1, sizeof(head));
    memset(vis, false, sizeof(vis));
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
    {
        scanf("%d %d", &a, &b);
        addedge(a, b);
        addedge(b, a);
    }
    dfs(0);
    memset(vis, false, sizeof(vis));
    dfs2(p);
    //printf("%d %d\n", max1, max2);
    printf("%d %d\n", n1, n1 - max1*max2);
    return 0;
}

如有错误请指明~   ฅ●ω●ฅ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值