E 缆车

题目描述:

在远离大陆的太平洋上,有一个风景优美的小岛。传说,小岛上的文明是这样发展起来的。第一代人沿着岛的坡度选择了n 个定居点,编号为1,2,…,n. 其中编号 i 定居点的高度就是i米。他们在定居点的附近修建了房屋,开辟了农田,种植了植物。第二代人在 n 个定居点之间修建了n-1条小路,每条小路连接两个定居点,且任意两个定居点之间都可以通过小路相互到达,互通有无。各个定居点不仅高度不同,而且距离非常远.随着技术的提高,第三代人将盘岛小路改造成可以通缆车的道路。这样不同定居点的人们不费力气就可以借助缆车,自由地到达任何一个定居点。为了纪念开辟文明的先辈,每年,小岛上都会举行一种特殊的仪式。每年的仪式会选择两个定居点x, y,人们将自己的思念和祝愿写成信件放入缆车,缆车将从定居点x 出发,沿着唯一的路径驶向定居点y。为了体会到翻山越岭的感觉, 岛民们希望缆车行车路线满足如下条件:缆车依次经过若干定居点a1, a2,…, ak,岛民们认为,如果存在i,在满足 1<i<k 条件下, a1< a2<……< ai 且 ai >ai+1 ……> aka1可以作为出发点,ak 可以作为终止点。岛民想要知道,存在多少种不同路径的仪式方案? 所谓两个仪式方案不同,是指在满足约束条件下,如果他们的出发节点不同,或者结束点不同。

输入描述:

第一行: T 表示以下有T组测试数据 ( 1≤ T ≤ 5 )
对每组数据,第1行: 一个整数n表示定居点个数。 接下来有n-1行,每行两个整数ai aj,表示定居点ai到定居点aj之间有一条缆车路线。1 ≤ n ≤ 2* 10^5

输出描述:

对每组测试数据,输出一个正整数,表示有多少种不同的仪式方案。

样例输入:

1
4
1 4
2 4
3 4

样例输出:

6

题目解析:

寻找每一个以较大节点的最大值的路径,分为两步dfs就出来了

上代码:

#include<bits/stdc++.h>
using namespace std;
long long n;
vector<long long> a[200005];
long long flag[200005];
long long biao[200005];
long long b[200005];
long long jiang[200005];
long long dfs(long long what)
{
    biao[what]=1;
    if(b[what])return b[what];
    if(flag[what]==0)return b[what]=1;
    b[what]=1;
    for(long long i=0;i<a[what].size();i++)
    {
        long long en=dfs(a[what][i]);
        b[what]+=en;
    }
    return b[what];
}//b表示他的链接的小型子节点中包括自己的子节点个数
long long zhao(long long what)
{
    if(jiang[what])return jiang[what];
    if(flag[what]==0)return jiang[what]=0;
    for(long long i=0;i<a[what].size();i++)
    {
        for(long long j=i+1;j<a[what].size();j++)
        {
            jiang[what]+=b[a[what][i]]*b[a[what][j]];
        }
    }
    return jiang[what];
}//jiang表示以此为最大值的路径个数
int main()
{
    long long t;
    scanf("%lld",&t);
    while(t--)
    {
        for(long long i=0;i<200005;i++)
        {
            a[i].clear();
        }
        memset(flag,0,sizeof(flag));
        memset(b,0,sizeof(b));
        memset(jiang,0,sizeof(jiang));
        memset(biao,0,sizeof(biao));//可能有点蠢的初始化,如果有更好的方法,麻烦留言,会调整
        scanf("%lld",&n);
        long long x,y;
        long long i,j;
        for(i=1;i<n;i++)
        {
            scanf("%lld%lld",&x,&y);
            if(x<y)
            {
                a[y].push_back(x);
                flag[y]++;
            }
            else 
            {
                a[x].push_back(y);
                flag[x]++;
             } 
        }
        long long sum=0;
        for(i=n;i>=1;i--)
        {
            if(biao[i]==0)
            dfs(i);
        }
        for(i=n;i>=1;i--)
        {
            sum+=zhao(i);
        }
        printf("%lld\n",sum*2);//起止点可以互换
    }
    return 0;
 }

如此图片中,9的下一级节点6,b[6]=3,b[7]=2,b[8]=3;
所以,以9位最大节点的路径个数为3乘3+3乘2+3乘2,同理,退出以6,7,8为最大节点的路径个数,相加,最后因为起止点可以互换,所以乘2

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值