Gym102028G Shortest Paths on Random Forests 生成函数、多项式Exp

传送门


神仙题……

考虑计算三个部分:1、\(n\)个点的森林的数量,这个是期望的分母;2、\(n\)个点的所有森林中存在最短路的点对的最短路径长度之和;3、\(n\)个点的所有路径中存在最短路的点对的个数之和,这个是用来计算需要取到\(m\)的点对的数量。

对于1,这个就直接对着树的数量的EGF做多项式exp即可。因为点之间有序所以用EGF,\(n\)个点的树的数量由Cayley定理就是\(n^{n-2}\)

对于3,考虑枚举一个连通块大小,那么这种连通块大小的所有树的存在最短路的点对之和就是\(n^{n-2} \binom{n}{2}\)。然后我们需要求这个连通块在哪些森林中出现过,我们就需要拼一个森林进去,所以直接拿这个的EGF跟1中求出来的多项式做一个卷积就可以了。

对于2,发现那个平方不是很好搞,于是可以考虑平方的组合意义,实际上就是在\(i,j\)路径上的边上有序地任取两条边。我们可以考虑先枚举两条边,然后再考虑这两条边会在哪些路径上做出贡献。注意到两条不重合的边会把树分为三个连通块,而两条重合的边会分为两个连通块,那么我们可以再次交换求和顺序,先枚举两个/三个连通块,然后考虑如何在这两个/三个连通块之间连边、选择\(i,j\)

考虑三个连通块的情况,两个连通块的情况类似。注意到如果三个连通块大小为\(a_1,a_2,a_3\),边固定为1连向2、2连向3,\(i\)在1、\(j\)在3,那么连边的方式就有\(a_1a_2 \times a_2a_3\)种,选择起点的方式有\(a_1\)种,选择终点的方式有\(a_3\)种,那么总贡献就是\(a_1^2a_2^2a_3^2\),只和连通块大小有关。不难再构造一个生成函数,每个位置表示大小为\(x\)的连通块的贡献,那么这个生成函数的平方和三次方就是选择两个连通块和三个连通块的方案。

那么我们就只要考虑这个连通块会出现在哪些森林里,和3过程一样卷上1求出来的多项式就可以了。

值得注意的一点是,求2的过程中,因为有序枚举这两条边是存在两种方案的,所以选择三个连通块的所有方案需要乘上2;在求2的过程中,点对\(i,j\)和点对\(j,i\)都会被计算,所以2的所有答案还要除以2。

代码

转载于:https://www.cnblogs.com/Itst/p/11006311.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
由于Policy gradient的loss函数通常是非常复杂的,取决于具体的环境和策略。因此,这里提供一个简单的CartPole-v0环境的Policy gradient的例子,并画出其loss函数。 import gym import numpy as np import tensorflow as tf # 创建CartPole环境 env = gym.make('CartPole-v0') # 定义超参数 learning_rate = 0.01 gamma = 0.99 num_episodes = 1000 # 定义神经网络 inputs = tf.placeholder(shape=[None, 4], dtype=tf.float32) W1 = tf.Variable(tf.random_normal([4, 16])) b1 = tf.Variable(tf.zeros([16])) hidden = tf.nn.relu(tf.matmul(inputs, W1) + b1) W2 = tf.Variable(tf.random_normal([16, 2])) b2 = tf.Variable(tf.zeros([2])) outputs = tf.nn.softmax(tf.matmul(hidden, W2) + b2) # 定义损失函数和优化器 actions = tf.placeholder(shape=[None], dtype=tf.int32) rewards = tf.placeholder(shape=[None], dtype=tf.float32) indices = tf.range(0, tf.shape(outputs)[0]) * tf.shape(outputs)[1] + actions act_prob = tf.gather(tf.reshape(outputs, [-1]), indices) loss = -tf.reduce_mean(tf.log(act_prob) * rewards) optimizer = tf.train.AdamOptimizer(learning_rate).minimize(loss) # 开始训练 sess = tf.Session() sess.run(tf.global_variables_initializer()) for episode in range(num_episodes): obs = env.reset() observations = [] actions_taken = [] rewards_received = [] done = False while not done: # 选择动作并执行 action_prob = sess.run(outputs, feed_dict={inputs: [obs]})[0] action = np.random.choice(np.arange(2), p=action_prob) new_obs, reward, done, info = env.step(action) # 保存观测值、动作和奖励 observations.append(obs) actions_taken.append(action) rewards_received.append(reward) obs = new_obs # 计算回报 returns = np.zeros_like(rewards_received) G = 0 for t in reversed(range(len(rewards_received))): G = gamma * G + rewards_received[t] returns[t] = G # 归一化回报 returns -= np.mean(returns) returns /= np.std(returns) # 计算损失并更新策略网络 _, l = sess.run([optimizer, loss], feed_dict={ inputs: np.array(observations), actions: np.array(actions_taken), rewards: returns}) print('Episode %d, loss: %f' % (episode + 1, l)) # 关闭环境和会话 env.close() sess.close() # 画出loss函数 import matplotlib.pyplot as plt x = np.arange(num_episodes) y = np.zeros(num_episodes) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) for episode in range(num_episodes): obs = env.reset() observations = [] actions_taken = [] rewards_received = [] done = False while not done: action_prob = sess.run(outputs, feed_dict={inputs: [obs]})[0] action = np.random.choice(np.arange(2), p=action_prob) new_obs, reward, done, info = env.step(action) observations.append(obs) actions_taken.append(action) rewards_received.append(reward) obs = new_obs returns = np.zeros_like(rewards_received) G = 0 for t in reversed(range(len(rewards_received))): G = gamma * G + rewards_received[t] returns[t] = G returns -= np.mean(returns) returns /= np.std(returns) _, l = sess.run([optimizer, loss], feed_dict={ inputs: np.array(observations), actions: np.array(actions_taken), rewards: returns}) y[episode] = l plt.plot(x, y) plt.xlabel('Episode') plt.ylabel('Loss') plt.show()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值