山东理工大学网络擂台赛——A.五军之战

山东理工大学网络擂台赛——A.五军之战

题目内容

在这里插入图片描述
在这里插入图片描述

个人AC程序

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int maxn = 2030;
typedef long long ll;
int n, u, v, leafCnt;
bool isVis[maxn];
vector<int> G[maxn];
vector<ll> roads;

#define min(a, b) (a) < (b) ? (a) : (b)

/// C(a, b) = a!/b!/(a-b)!
/// Called : C(leafCnt, 5)
ll getSchamesCount(ll a, ll b)
{
    ll ret = 1;
    for(ll i = 1;i <= b;++i)
    {
        ret *= a;
        ret /= i;
        a--;
    }
    return ret;
}

void dfs(int curPos, ll curLen)
{
    if(1 == (int)G[curPos].size() && 1 != curPos)
    {
        roads.push_back(curLen);
        return ;
    }
    for(int i = 0;i < (int)G[curPos].size();++i)
    {
        int nxtPos = G[curPos][i];
        if(!isVis[nxtPos])
        {
            isVis[nxtPos] = true;
            dfs(nxtPos, curLen + 1);
            isVis[nxtPos] = false;
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    isVis[1] = true;
    cin >> n;
    for(int i = 1;i < n;++i)
    {
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    for(int i = 2;i <= n;++i)
    {
        if(1 == (int)G[i].size())
        {
            leafCnt++;
        }
    }
    dfs(1, 0);
    sort(roads.begin(), roads.end());
    ll res1 = 0, res2 = 0;
    if(leafCnt > 5)
    {
        res1 = getSchamesCount(leafCnt, 5);
        for(int i = 0;i < 5;++i)
        {
            res2 += roads[i];
        }
    }
    else
    {
        res1 = 1;
        for(int i = 0;i < leafCnt;++i)
        {
            res2 += roads[i];
        }
    }
    cout << res1 << ' ' << res2 << endl;
    return 0;
}

在这里插入图片描述

算法分析与设计

这题是一个很简单的深度优先遍历的习题,可是我仍是WA了不少次,羞愧啊!html

问题一: 如何计算出方案数?ios

只须要计算有多少个叶子节点 c n t cnt cnt,而后计算 C ( c n t , 5 ) C(cnt, 5) C(cnt,5),若是 c n t < 5 cnt < 5 cnt<5则直接输出1,由于此时没有足够的叶子结点去排兵布阵。算法

而后此题不要求对组合数取模,说明组合数计算的中间结果不会超过long long,那么只须要一遍循环计算便可!数组

问题2: 如何计算出有多少个叶子节点?markdown

叶子结点的度为1,只须要维护一个degree数组就能够解决,也就是对数组遍历,若是值为1则累计增长一个叶子节点。网络

固然,更好的办法是利用图的数据结构,查看邻接表的邻接规模,也就是vector的size就能够判断是不是叶子节点,由于叶子节点的size必定是1,而除了根节点之外的普通结点必定不是1!数据结构

注意咱们说的除了根节点之外的结点,由于若是这棵树退化成链,则根节点也是度为1的结点!ide

问题3: 如何计算最短的路径?atom

这题只须要计算最短的五个(或更少)排兵布阵的叶子结点到根节点的路径和,而后根节点的数量确定不超过 n / 2 = 1010 n/2=1010 n/2=1010,因此用数组存下全部叶子节点到根节点的路径而后排序获得最短的几个累计便可!spa

若是排兵布阵的叶子结点不少,不必定只有五个的时候!就是典型的Top K问题,就维护一个大小为K的小顶堆,每次插入的时间是 l o g ( n ) log(n) log(n),计算的总时间是 K + l o g ( n ) K+log(n) K+log(n),这要比维护数组排序的 n + n l o g ( n ) n+nlog(n) n+nlog(n)要好不少!

结束语

有想要探讨、合做的小伙伴能够关注我,有问题能够发邮件给我,个人邮箱是:2329313458@qq.com

相关文章
相关标签/搜索