(树形DP)【HDU 6446】Tree and Permutation

本文介绍了一道经典组合数学与图论结合的问题——HDU 6446,该题要求计算一棵树上所有节点的全排列路径之和。通过观察规律,发现每条边在所有路径中出现的次数为2*(N-1)!,进而提出一种高效算法。代码使用C++实现,并特别注意了大数运算中的溢出问题。

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6446

题目大意:给一棵N个节点N-1条边的树,把1~N的全排列的最短路径求和,也就是比如N=3的话,路径排列就有【1-2-3】,【1-3-2】,【2-1-3】,【2-3-1】,【3-1-2】,【3-2-1】这N!种。比赛的时候打了个表发现规律就是每条边会出现2*(N-1)!次,所以计算出树上任意两点间的距离和再乘上2*(N-1)!就可以了,搜这个找到了个HDU 2376是类似做法,然而有的地方没转换成LL所以WA了好几发。。还是罗大佬他们队直接改了下我的代码过了。。基本代码是一样的没什么变动,注意MOD和LL就好了。

 

/*
* @Author: SamsonHo
* @Date:   2018-09-11-08.36.01
* @URL:
*/
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int MAXN = 1e5+10;
const int MOD = 1e9+7;
int n;
LL sum[MAXN],dp[MAXN];
vector<pair<int,int> > e[MAXN];
void dfs(int cur,int father)
{
    sum[cur] = 1;
    int len = e[cur].size();
    for(int i = 0; i < len; ++i)
    {
        int v = e[cur][i].first;
        if(v == father) continue;
        dfs(v,cur);
        sum[cur] = (sum[cur]+sum[v])%MOD;
        dp[cur] = (dp[cur] + (dp[v]*1LL + 1LL*(sum[v]*(n-sum[v])*e[cur][i].second%MOD)))%MOD;
    }
}

int main(void)
{
    while(~scanf("%d",&n))
    {
        for(int i = 0; i <= n; ++i)
            e[i].clear();
        memset(sum,0,sizeof sum);
        memset(dp,0,sizeof dp);
        int x,y,l;
        for(int i = 0; i < n-1; ++i)
        {
            scanf("%d%d%d",&x,&y,&l);
            e[x].push_back(make_pair(y,l));
            e[y].push_back(make_pair(x,l));
        }
        dfs(1,0);
        LL tmp = 1;
        for(int i = 1; i <= n-1; ++i)
            tmp = tmp*i%MOD;
        tmp = tmp*2%MOD;
        printf("%lld\n",dp[1]*tmp%MOD);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值