Tree and Permutation

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1581    Accepted Submission(s): 588


 

Problem Description

There are N vertices connected by N−1 edges, each edge has its own length.
The set { 1,2,3,…,N } contains a total of N! unique permutations, let’s say the i -th permutation is Pi and Pi,j is its j -th number.
For the i -th permutation, it can be a traverse sequence of the tree with N vertices, which means we can go from the Pi,1 -th vertex to the Pi,2 -th vertex by the shortest path, then go to the Pi,3 -th vertex ( also by the shortest path ) , and so on. Finally we’ll reach the Pi,N -th vertex, let’s define the total distance of this route as D(Pi) , so please calculate the sum of D(Pi) for all N! permutations.

 

 

Input

There are 10 test cases at most.
The first line of each test case contains one integer N ( 1≤N≤105 ) .
For the next N−1 lines, each line contains three integer X , Y and L , which means there is an edge between X -th vertex and Y -th of length L ( 1≤X,Y≤N,1≤L≤109 ) .

 

 

Output

For each test case, print the answer module 109+7 in one line.

 

 

Sample Input

 

3 1 2 1 2 3 1 3 1 2 1 1 3 2

 

 

Sample Output

 

16 24

 

 

Source

2018中国大学生程序设计竞赛 - 网络选拔赛

 

题意:有一棵n个顶点的树,给出两个顶点之间的距离,然后将这n个数排列后算出所有排列的路径距离和(比如有3个顶点的数,全排列为123,132,213,231,312,321),然后结果就是所有排列的结果(比如123这个排列的结果就是顶点1到顶点2的距离加上顶点2到顶点3的距离)加起来,如果顺着题意这样阶梯的话暴力会超时,我们只需要转化一下就可以:题意要求所有排列的结果,我们只需要想每条边的距离在所有全排列中共用了几次,然后乘以这条边的权重就是这条边在所有排列中所贡献的距离和,其他边同理,接下来通过排列的数学知识我们知道任意两个相邻顶点的所有排列共出现了(n-1)!*2的次(乘以2是因为相邻的两个顶点可以交换顺序),这样的话我们的问题就转化成在这个树中任意两个顶点之间最短距离的和,最后乘以(n-1)!*2就是我们要的答案。

 

#include<vector>
#include<string.h>
#include<iostream>
using namespace std;
const int N = 1e5 + 5;
typedef long long int LL;
const int MOD = 1e9 + 7;
LL jc[N];
LL son[N];
struct Edge {
	int v;
	int w;
}edge;
vector<Edge>ve[N];
	int n;
	LL dfs(int current, int father,int pre_dis) {//current代表当前节点,father父节点,pre_dis代表父节点与当前节点之间的权重
		LL result=0;
		LL juli;
		for (int i = 0; i < ve[current].size(); i++) {
			int next = ve[current][i].v;//记录与current节点相邻的节点
			juli = ve[current][i].w;
			if (next ==father)
				continue;
			result+=dfs(next, current,juli);
			son[current] += son[next] + 1;//当前节点等于子节点的个数+子节点它本身(1)
		}
		//当所有节点遍历完之后统计每条边被用的次数
		 result+=(((son[current] + 1)%MOD)*(n - (son[current] + 1))%MOD) % MOD*(pre_dis) % MOD;

            		return result;
 	}

int main() {
	
	freopen("Text.txt", "r", stdin);
	jc[1] = 1;
	for (int i = 2; i <= 1e5; i++) {//存取n个顶点的阶乘
		jc[i] = (jc[i - 1] * i)%MOD;
	}
	while (cin >> n) {
		if (n == 1)
			cout << 0 << endl;
		else {
			memset(son, 0, sizeof(son));
			for (int i = 0; i <= 1e5; i++) {//注意每次while循环清空不定数组
				ve[i].clear();
			}
			int v1, v2, dis;
			for (int i = 1; i < n; i++) {
				scanf("%d%d%d", &v1, &v2, &dis);//这个地方一定要用scanf读取数据,用cin会超时
				ve[v1].push_back(Edge{ v2,dis });
				ve[v2].push_back(Edge{ v1,dis });
			}
			printf("%lld\n", (((dfs(1, 0,0) * 2) % MOD)*jc[n - 1]) % MOD);
		}
	}
	return 0;

}

 

 
 

 

import numpy as np class Node: j = None theta = None p = None left = None right = None class DecisionTreeBase: def __init__(self, max_depth, feature_sample_rate, get_score): self.max_depth = max_depth self.feature_sample_rate = feature_sample_rate self.get_score = get_score def split_data(self, j, theta, X, idx): idx1, idx2 = list(), list() for i in idx: value = X[i][j] if value <= theta: idx1.append(i) else: idx2.append(i) return idx1, idx2 def get_random_features(self, n): shuffled = np.random.permutation(n) size = int(self.feature_sample_rate * n) selected = shuffled[:size] return selected def find_best_split(self, X, y, idx): m, n = X.shape best_score = float("inf") best_j = -1 best_theta = float("inf") best_idx1, best_idx2 = list(), list() selected_j = self.get_random_features(n) for j in selected_j: thetas = set([x[j] for x in X]) for theta in thetas: idx1, idx2 = self.split_data(j, theta, X, idx) if min(len(idx1), len(idx2)) == 0 : continue score1, score2 = self.get_score(y, idx1), self.get_score(y, idx2) w = 1.0 * len(idx1) / len(idx) score = w * score1 + (1-w) * score2 if score < best_score: best_score = score best_j = j best_theta = theta best_idx1 = idx1 best_idx2 = idx2 return best_j, best_theta, best_idx1, best_idx2, best_score def generate_tree(self, X, y, idx, d): r = Node() r.p = np.average(y[idx], axis=0) if d == 0 or len(idx)<2: return r current_score = self.get_score(y, idx) j, theta, idx1, idx2, score = self.find_best_split(X, y, idx) if score >= current_score: return r r.j = j r.theta = theta r.left = self.generate_tree(X, y, idx1, d-1) r.right = self.generate_tree(X, y, idx2, d-1) return r def fit(self, X, y): self.root = self.generate_tree(X, y, range(len(X)), self.max_depth) def get_prediction(self, r, x): if r.left == None and r.right == None: return r.p value = x[r.j] if value <= r.theta: return self.get_prediction(r.left, x) else: return self.get_prediction(r.right, x) def predict(self, X): y = list() for i in range(len(X)): y.append(self.get_prediction(self.root, X[i])) return np.array(y)
最新发布
06-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值