这一节使用TensorFlow中的函数搭建一个简单的RNN网络,使用一串随机的模拟数据作为原始信号,让RNN网络来拟合其对应的回声信号。

样本数据为一串随机的由0,1组成的数字,将其当成发射出去的一串信号。当碰到阻挡被反弹回来时,会收到原始信号的回声。

如果步长为3,那么输入和输出的序列如下图所示:

原序列 0 1 1 0 1 0 1 1 0 0 1 1 0 1 1
回声序列 null null null 0 1 1 0 1 0 1 1 0 0 1 1

如上表所示,回声序列的前三项是null,原序列的第一个信号为0,对应的是回声序列的第四项,即回声序列的每一个数都比原序列滞后3个时序。本例的任务就是把序列截取出来,对于每个原序列来预测它的回声序列。。

构建的网络结构如下图所示:

上图中,初始的输入有5个,xt个为t时刻输入序列值,另外4个为t-1时刻隐藏层的输出值ht-1。通过一层具有4个节点的RNN网络,再接一个全连接输出两个类别,分别表示输出0,和1类别的概率。这样每个序列都会有一个对应的预测分类值,最终将整个序列生成了预测序列。

下面我们会演示一个例子,这里随机生成一个具有50000个序列样本数据,然后根据原序列生成50000个回声序列样本数据。我们每个训练截取15个序列作为一个样本,我们设置小批量大小batch_size为5。

  • 我们把50000个序列,转换为5x10000的数组。
  • 对数组的每一行按长度为15进行分割,每一个小批量含有5x15个序列。
  • 针对每一小批量的序列,我们使用RNN网络开始迭代,迭代每一个批次中的每一组序列(5x1)。

注意这里面的5就是我们设置的batch_size大小,这和我们之前在CNN以及DNN网络中的batch_size是一样的,即一次训练使用batch_size个样本。

下面是一个小批量的原序列数据和回声序列数据,这里回声序列的前三个序列值是无效的,这主要是与我们原序列切割方式有关的。

一 定义参数并生成样本数据

  1. np.random.seed(0)
  2. '''
  3. 一 定义参数生成样本数据
  4. '''
  5.  
  6. num_epochs = 5 #迭代轮数
  7. total_series_length = 50000 #序列样本数据长度
  8. truncated_backprop_length = 15 #测试时截取数据长度
  9. state_size = 4 #中间状态长度
  10. num_classes = 2 #输出类别个数
  11. echo_step = 3 #回声步长
  12. batch_size = 5 #小批量大小
  13. learning_rate = 0.4 #学习率
  14. num_batches =total_series_length//batch_size//truncated_backprop_length #计算一轮可以分为多少批
  15.  
  16. def generate_date():
  17. '''
  18. 生成原序列和回声序列数据,回声序列滞后原序列echo_step个步长
  19.  
  20. 返回原序列和回声序列组成的元组
  21. '''
  22. #生成原序列样本数据 random.choice()随机选取内容从0和1中选取total_series_length个数据,0,1数据的概率都是0.5
  23. x = np.array(np.random.choice(2,total_series_length,p=[0.5,0.5]))
  24. #向右循环移位 如11110000->00011110
  25. y =np.roll(x,echo_step)
  26. #回声序列,前echo_step个数据清0
  27. y[0:echo_step] = 0
  28.  
  29. x = x.reshape((batch_size,-1)) #5x10000
  30. #print(x)
  31. y = y.reshape((batch_size,-1)) #5x10000
  32. #print(y)
  33. return (x,y)

二 定义占位符处理输入数据

定义三个占位符,batch_x为原始序列,batch_y为回声序列真实值,init_state为循环节点的初始值。batch_x是逐个输入网络的,所以需要将输进去的数据打散,按照时间序列变成15个数组,每个数组有batch_size个元素,进行统一批处理。

  1. '''
  2. 二 定义占位符处理输入数据
  3. '''
  4. batch_x = tf.placeholder(dtype=tf.float32,shape=[batch_size,truncated_backprop_length]) #原始序列
  5. batch_y = tf.placeholder(dtype=tf.int32,shape=[batch_size,truncated_backprop_length]) #回声序列 作为标签
  6. init_state = tf.placeholder(dtype=tf.float32,shape=[batch_size,state_size]) #循环节点的初始状态值
  7.  
  8. #将batch_x沿axis = 1(列)的轴进行拆分 返回一个list 每个元素都是一个数组 [(5,),(5,)....] 一共15个元素,即15个序列
  9. inputs_series = tf.unstack(batch_x,axis=1)
  10. labels_series = tf.unstack(batch_y,axis=1)

三 定义网络结构

定义一层循环与一层全网络连接。由于数据是一个二维数组序列,所以需要通过循环将输入数据按照原有序列逐个输入网络,并输出对应的predictions序列,同样的,对于每个序列值都要对其做loss计算,在loss计算使用了spare_softmax_cross_entropy_with_logits函数,因为label的最大值正好是1,而且是一位的,就不需要在使用one_hot编码了,最终将所有的loss均值放入优化器中。

  1. '''
  2. 三 定义RNN网络结构
  3.  
  4. 一个输入样本由15个输入序列组成 一个小批量包含5个输入样本
  5. '''
  6. current_state = init_state #存放当前的状态
  7. predictions_series = [] #存放一个小批量中每个输入样本的预测序列值 每个元素为5x2 共有15个元素
  8. losses = [] #存放一个小批量中每个输入样本训练的损失值 每个元素是一个标量,共有15个元素
  9.  
  10. #使用一个循环,按照序列逐个输入
  11. for current_input,labels in zip(inputs_series,labels_series):
  12. #确定形状为batch_size x 1
  13. current_input = tf.reshape(current_input,[batch_size,1])
  14. '''
  15. 加入初始状态
  16. 5 x 1序列值和 5 x 4中间状态 按列连接,得到 5 x 5数组 构成输入数据
  17. '''
  18. input_and_state_concatenated = tf.concat([current_input,current_state],1)
  19. #隐藏层激活函数选择tanh 5x4
  20. next_state = tf.contrib.layers.fully_connected(input_and_state_concatenated,state_size,activation_fn = tf.tanh)
  21. current_state = next_state
  22. #输出层 激活函数选择None,即直接输出 5x2
  23. logits = tf.contrib.layers.fully_connected(next_state,num_classes,activation_fn = None)
  24. #计算代价
  25. loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(labels=labels,logits = logits))
  26. losses.append(loss)
  27. #经过softmax计算预测值 5x2 注意这里并不是标签值 这里是one_hot编码
  28. predictions = tf.nn.softmax(logits)
  29. predictions_series.append(predictions)
  30.  
  31. total_loss = tf.reduce_mean(losses)
  32. train_step = tf.train.AdagradOptimizer(learning_rate).minimize(total_loss)

四  建立session训练数据并可视化输出

建立session,初始化RNN循环节点的值为0。总样本迭代5轮,每一轮迭代完调用plot函数生成图像。

  1. '''
  2. 四 建立session训练数据
  3. '''
  4. with tf.Session() as sess:
  5. sess.run(tf.global_variables_initializer())
  6. loss_list = [] #list 存放每一小批量的代价值
  7.  
  8. #开始迭代每一轮
  9. for epoch_idx in range(num_epochs):
  10. #生成原序列和回声序列数据
  11. x,y = generate_date()
  12.  
  13. #初始化循环节点状态值
  14. _current_state = np.zeros((batch_size,state_size))
  15.  
  16. print('New date,epoch',epoch_idx)
  17.  
  18. #迭代每一小批量
  19. for batch_idx in range(num_batches):
  20. #计算当前batch的起始索引
  21. start_idx = batch_idx * truncated_backprop_length
  22. #计算当前batch的结束索引
  23. end_idx = start_idx + truncated_backprop_length
  24.  
  25. #当前批次的原序列值
  26. batchx = x[:,start_idx:end_idx]
  27. #当前批次的回声序列值
  28. batchy = y[:,start_idx:end_idx]
  29.  
  30. #开始训练当前批次样本
  31. _total_loss,_train_step,_current_state,_predictions_series = sess.run(
  32. [total_loss,train_step,current_state,predictions_series],
  33. feed_dict = {
  34. batch_x:batchx,
  35. batch_y:batchy,
  36. init_state:_current_state
  37. })
  38.  
  39. loss_list.append(_total_loss)
  40.  
  41. if batch_idx % 100 == 0:
  42. print('Step {0} Loss {1}'.format(batch_idx,_total_loss))
  43. #可视化输出
  44. plot(loss_list,_predictions_series,batchx,batchy)
  45. #print(batchx)
  46. #print(batchy)
  1. def plot(loss_list, predictions_series, batchx, batchy):
  2. '''
  3. 绘制一个小批量中每一个原序列样本,回声序列样本,预测序列样本图像
  4.  
  5. args:
  6. loss_list:list 存放每一个批次训练的代价值
  7. predictions_series:list长度为5 存放一个批次中每个输入序列的预测序列值 注意这里每个元素(5x2)都是one_hot编码
  8. batchx:当前批次的原序列 5x15
  9. batchy:当前批次的回声序列 5x15
  10. '''
  11. plt.figure(figsize=(3.2*3,2.4*2))
  12. #创建子图 2行3列选择第一个 绘制代价值
  13. plt.subplot(2, 3, 1)
  14. plt.cla()
  15. plt.plot(loss_list)
  16.  
  17. #迭代每一个序列 循环5次
  18. for batch_series_idx in range(batch_size):
  19. #获取第batch_series_idx个序列的预测值(one_hot编码) 15x2
  20. one_hot_output_series = np.array(predictions_series)[:, batch_series_idx, :]
  21. #转换为标签值 (15,)
  22. single_output_series = np.array([(1 if out[0] < 0.5 else 0) for out in one_hot_output_series])
  23.  
  24. #绘制第batch_series_idx + 2个子图
  25. plt.subplot(2, 3, batch_series_idx + 2)
  26. plt.cla()
  27. #设置x轴 y轴坐标值范围
  28. plt.axis([0, truncated_backprop_length, 0, 2])
  29. #获取原序列x坐标值
  30. left_offset = range(truncated_backprop_length)
  31. #获取回声序列x坐标值 滞后3个步长
  32. left_offset2 = range(echo_step,truncated_backprop_length + echo_step)
  33.  
  34. label1 = "past values"
  35. label2 = "True echo values"
  36. label3 = "Predictions"
  37. #绘制原序列
  38. plt.plot(left_offset2, batchx[batch_series_idx, :]*0.2+1.5, "o--b", label=label1)
  39. #绘制真实回声序列
  40. plt.plot(left_offset, batchy[batch_series_idx, :]*0.2+0.8,"x--b", label=label2)
  41. #绘制预测回声序列
  42. plt.plot(left_offset, single_output_series*0.2+0.1 , "o--r", label=label3)
  43.  
  44. plt.legend(loc='best')
  45. plt.show()

函数中将输入的原序列,回声序列和预测的序列同时输出在图像中。按照小批量样本的个数生成图像。为了让三个序列看起来更明显,将其缩放0.2,并且调节每个图像的高度。同时将原始序列在显示中滞后echo_step个序列,将三个图像放在同一序列顺序比较。

如上图,最下面的是预测的序列,中间的为回声序列,从图像上可以看出预测序列和回声序列几乎相同,表明RNN网络已经完全可以学习到回声的规则。

完整代码:

  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Tue May 8 08:45:40 2018
  4.  
  5. @author: zy
  6. """
  7.  
  8. '''
  9. 使用RNN网络拟合回声信号序列
  10.  
  11. 使用一串随机的模拟数据作为原始信号,让RNN网络来拟合其对应的回声信号
  12. 样本数据为一串随机的由0,1组成的数字,将其当成发射出去的一串信号。当碰到阻挡被反弹回来时,会收到原始信号的回音
  13.  
  14. 如果步长为3,那么输入和输出的序列序列如下:
  15. 原序列 0 1 1 | 0 1 0 ..... 1
  16. 回声序列 null null null | 0 1 1 ..... 0
  17. '''
  18.  
  19. import tensorflow as tf
  20. import numpy as np
  21. import matplotlib.pyplot as plt
  22.  
  23. np.random.seed(0)
  24. '''
  25. 一 定义参数生成样本数据
  26. '''
  27.  
  28. num_epochs = 5 #迭代轮数
  29. total_series_length = 50000 #序列样本数据长度
  30. truncated_backprop_length = 15 #测试时截取数据长度
  31. state_size = 4 #中间状态长度
  32. num_classes = 2 #输出类别个数
  33. echo_step = 3 #回声步长
  34. batch_size = 5 #小批量大小
  35. learning_rate = 0.4 #学习率
  36. num_batches =total_series_length//batch_size//truncated_backprop_length #计算一轮可以分为多少批
  37.  
  38. def generate_date():
  39. '''
  40. 生成原序列和回声序列数据,回声序列滞后原序列echo_step个步长
  41.  
  42. 返回原序列和回声序列组成的元组
  43. '''
  44. #生成原序列样本数据 random.choice()随机选取内容从0和1中选取total_series_length个数据,0,1数据的概率都是0.5
  45. x = np.array(np.random.choice(2,total_series_length,p=[0.5,0.5]))
  46. #向右循环移位 如11110000->00011110
  47. y =np.roll(x,echo_step)
  48. #回声序列,前echo_step个数据清0
  49. y[0:echo_step] = 0
  50.  
  51. x = x.reshape((batch_size,-1)) #5x10000
  52. #print(x)
  53. y = y.reshape((batch_size,-1)) #5x10000
  54. #print(y)
  55. return (x,y)
  56.  
  57. '''
  58. 二 定义占位符处理输入数据
  59. '''
  60. batch_x = tf.placeholder(dtype=tf.float32,shape=[batch_size,truncated_backprop_length]) #原始序列
  61. batch_y = tf.placeholder(dtype=tf.int32,shape=[batch_size,truncated_backprop_length]) #回声序列 作为标签
  62. init_state = tf.placeholder(dtype=tf.float32,shape=[batch_size,state_size]) #循环节点的初始状态值
  63.  
  64. #将batch_x沿axis = 1(列)的轴进行拆分 返回一个list 每个元素都是一个数组 [(5,),(5,)....] 一共15个元素,即15个序列
  65. inputs_series = tf.unstack(batch_x,axis=1)
  66. labels_series = tf.unstack(batch_y,axis=1)
  67.  
  68. '''
  69. 三 定义RNN网络结构
  70.  
  71. 一个输入样本由15个输入序列组成 一个小批量包含5个输入样本
  72. '''
  73. current_state = init_state #存放当前的状态
  74. predictions_series = [] #存放一个小批量中每个输入样本的预测序列值 每个元素为5x2 共有15个元素
  75. losses = [] #存放一个小批量中每个输入样本训练的损失值 每个元素是一个标量,共有15个元素
  76.  
  77. #使用一个循环,按照序列逐个输入
  78. for current_input,labels in zip(inputs_series,labels_series):
  79. #确定形状为batch_size x 1
  80. current_input = tf.reshape(current_input,[batch_size,1])
  81. '''
  82. 加入初始状态
  83. 5 x 1序列值和 5 x 4中间状态 按列连接,得到 5 x 5数组 构成输入数据
  84. '''
  85. input_and_state_concatenated = tf.concat([current_input,current_state],1)
  86. #隐藏层激活函数选择tanh 5x4
  87. next_state = tf.contrib.layers.fully_connected(input_and_state_concatenated,state_size,activation_fn = tf.tanh)
  88. current_state = next_state
  89. #输出层 激活函数选择None,即直接输出 5x2
  90. logits = tf.contrib.layers.fully_connected(next_state,num_classes,activation_fn = None)
  91. #计算代价
  92. loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(labels=labels,logits = logits))
  93. losses.append(loss)
  94. #经过softmax计算预测值 5x2 注意这里并不是标签值 这里是one_hot编码
  95. predictions = tf.nn.softmax(logits)
  96.  
  97. predictions_series.append(predictions)
  98.  
  99. total_loss = tf.reduce_mean(losses)
  100. train_step = tf.train.AdagradOptimizer(learning_rate).minimize(total_loss)
  101.  
  102. def plot(loss_list, predictions_series, batchx, batchy):
  103. '''
  104. 绘制一个小批量中每一个原序列样本,回声序列样本,预测序列样本图像
  105.  
  106. args:
  107. loss_list:list 存放每一个批次训练的代价值
  108. predictions_series:list长度为5 存放一个批次中每个输入序列的预测序列值 注意这里每个元素(5x2)都是one_hot编码
  109. batchx:当前批次的原序列 5x15
  110. batchy:当前批次的回声序列 5x15
  111. '''
  112. plt.figure(figsize=(3.2*3,2.4*2))
  113. #创建子图 2行3列选择第一个 绘制代价值
  114. plt.subplot(2, 3, 1)
  115. plt.cla()
  116. plt.plot(loss_list)
  117.  
  118. #迭代每一个序列 循环5次
  119. for batch_series_idx in range(batch_size):
  120. #获取第batch_series_idx个序列的预测值(one_hot编码) 15x2
  121. one_hot_output_series = np.array(predictions_series)[:, batch_series_idx, :]
  122. #转换为标签值 (15,)
  123. single_output_series = np.array([(1 if out[0] < 0.5 else 0) for out in one_hot_output_series])
  124.  
  125. #绘制第batch_series_idx + 2个子图
  126. plt.subplot(2, 3, batch_series_idx + 2)
  127. plt.cla()
  128. #设置x轴 y轴坐标值范围
  129. plt.axis([0, truncated_backprop_length, 0, 2])
  130. #获取原序列x坐标值
  131. left_offset = range(truncated_backprop_length)
  132. #获取回声序列x坐标值 滞后3个步长
  133. left_offset2 = range(echo_step,truncated_backprop_length + echo_step)
  134.  
  135. label1 = "past values"
  136. label2 = "True echo values"
  137. label3 = "Predictions"
  138. #绘制原序列
  139. plt.plot(left_offset2, batchx[batch_series_idx, :]*0.2+1.5, "o--b", label=label1)
  140. #绘制真实回声序列
  141. plt.plot(left_offset, batchy[batch_series_idx, :]*0.2+0.8,"x--b", label=label2)
  142. #绘制预测回声序列
  143. plt.plot(left_offset, single_output_series*0.2+0.1 , "o--r", label=label3)
  144.  
  145. plt.legend(loc='best')
  146. plt.show()
  147.  
  148. '''
  149. 四 建立session训练数据
  150. '''
  151. with tf.Session() as sess:
  152. sess.run(tf.global_variables_initializer())
  153. loss_list = [] #list 存放每一小批量的代价值
  154.  
  155. #开始迭代每一轮
  156. for epoch_idx in range(num_epochs):
  157. #生成原序列和回声序列数据
  158. x,y = generate_date()
  159.  
  160. #初始化循环节点状态值
  161. _current_state = np.zeros((batch_size,state_size))
  162.  
  163. print('New date,epoch',epoch_idx)
  164.  
  165. #迭代每一小批量
  166. for batch_idx in range(num_batches):
  167. #计算当前batch的起始索引
  168. start_idx = batch_idx * truncated_backprop_length
  169. #计算当前batch的结束索引
  170. end_idx = start_idx + truncated_backprop_length
  171.  
  172. #当前批次的原序列值
  173. batchx = x[:,start_idx:end_idx]
  174. #当前批次的回声序列值
  175. batchy = y[:,start_idx:end_idx]
  176.  
  177. #开始训练当前批次样本
  178. _total_loss,_train_step,_current_state,_predictions_series = sess.run(
  179. [total_loss,train_step,current_state,predictions_series],
  180. feed_dict = {
  181. batch_x:batchx,
  182. batch_y:batchy,
  183. init_state:_current_state
  184. })
  185.  
  186. loss_list.append(_total_loss)
  187.  
  188. if batch_idx % 100 == 0:
  189. print('Step {0} Loss {1}'.format(batch_idx,_total_loss))
  190. #可视化输出
  191. plot(loss_list,_predictions_series,batchx,batchy)
  192. #print(batchx)
  193. #print(batchy)

第二十节,使用RNN网络拟合回声信号序列的更多相关文章

  1. centos LAMP第二部分apache配置 下载discuz!配置第一个虚拟主机 安装Discuz! 用户认证 配置域名跳转 配置apache的访问日志 配置静态文件缓存 配置防盗链 访问控制 apache rewrite 配置开机启动apache tcpdump 第二十节课

    centos    LAMP第二部分apache配置  下载discuz!配置第一个虚拟主机 安装Discuz! 用户认证 配置域名跳转  配置apache的访问日志  配置静态文件缓存  配置防盗链 ...

  2. 大白话5分钟带你走进人工智能-第二十节逻辑回归和Softmax多分类问题(5)

                                                        大白话5分钟带你走进人工智能-第二十节逻辑回归和Softmax多分类问题(5) 上一节中,我们讲 ...

  3. 风炫安全WEB安全学习第二十节课 反射型XSS讲解

    风炫安全WEB安全学习第二十节课 反射型XSS讲解 反射性xss演示 原理讲解 如果一个应用程序使用动态页面向用户显示错误消息,就会造成一种常见的XSS漏洞.通常,该页面会使用一个包含消息文本的参数, ...

  4. 第十节课-RNN介绍

    2017-08-21 这次的课程介绍了RNN的相关知识: 首先是RNN的几种模型: 分别又不同的应用场景,包括机器翻译,视频的分类... RNN的解释: 主要的特点就是用到了上一个隐含状态的信息,所以 ...

  5. 第二十节:Asp.Net Core WebApi生成在线文档

    一. 基本概念 1.背景 使用 Web API 时,了解其各种方法对开发人员来说可能是一项挑战. Swagger 也称为OpenAPI,解决了为 Web API 生成有用文档和帮助页的问题. 它具有诸 ...

  6. [ExtJS5学习笔记]第二十节 Extjs5配合数组的push方法,动态创建并加载组件

    本文地址:http://blog.csdn.net/sushengmiyan/article/details/39226773 官方例子:http://docs.sencha.com/extjs/5. ...

  7. 第二十节,基本数据类型,集合set、综合应用新数据更新老数据

    基本数据类型,集合set.综合应用新数据更新老数据 创建两个字典新数据,更新原始数据,a为原始数据,b为新数据 1,分别获取到a字典和b字典的key(键),将两个字典的键分别转换成两个集合 2,找出a ...

  8. 第二十节: 深入理解并发机制以及解决方案(锁机制、EF自有机制、队列模式等)

    一. 理解并发机制 1. 什么是并发,并发与多线程有什么关系? ①. 先从广义上来说,或者从实际场景上来说. 高并发通常是海量用户同时访问(比如:12306买票.淘宝的双十一抢购),如果把一个用户看做 ...

  9. 第二十节:详细讲解String和StringBuffer和StringBuilder的使用

    前言 在 Java中的字符串属于对象,那么Java 中提供了 String 类来创建和操作字符串,即是使用对象:因为String类修饰的字符一旦被创建就不可改变,所以当对字符串进行修改的时候,需要使用 ...

随机推荐

  1. nginx反向代理proxy_pass的问题

    起因:今天企业部署一个项目,用的nginx做的反向代理,配置如下: 测试结果令人失望,IP:端口 能访问项目,域名:端口 也能访问 ,但是 域名/接口名 访问失败 ################## ...

  2. JavaScript控制阻止表单提交

    1.在表单上使用onSubmit方法 <?php $form = ActiveForm::begin([ 'options'=>[ 'class' => 'form-horizont ...

  3. Quick Introduction to SQL Server Profiler

    Introduction to Profiler SQL Server Profiler — or just Profiler — is a tool that can help monitor al ...

  4. Python Argparse模块

    argparse模块 在Python中,argparse模块是标准库中用来解析命令行参数的模块,用来替代已经过时的optparse模块.argparse模块能够根据程序中的定义从sys.argv中解析 ...

  5. BZOJ2428[HAOI2006]均分数据——模拟退火

    题目描述 已知N个正整数:A1.A2.…….An .今要将它们分成M组,使得各组数据的数值和最平均,即各组的均方差最小.均方差公式如下: ,其中σ为均方差,是各组数据和的平均值,xi为第i组数据的数值 ...

  6. jsp大学作业:jsp编写单选,复选判断题及得分情况

    project_1_1.jsp <%@ page contentType="text/html;charset=utf-8" language="java" ...

  7. Scrapy爬取伯乐在线文章

    首先搭建虚拟环境,创建工程 scrapy startproject ArticleSpider cd ArticleSpider scrapy genspider jobbole blog.jobbo ...

  8. hdu 5877 Weak Pair (Treap)

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=5877 题面; Weak Pair Time Limit: 4000/2000 MS (Java/Other ...

  9. reactNative 基础

    参考:中文网,极客 一 . 基本程序: import React, { Component } from 'react'; import { Text } from 'react-native'; e ...

  10. BZOJ4671 异或图(容斥+线性基)

    题意 定义两个结点数相同的图 \(G_1\) 与图 \(G_2\) 的异或为一个新的图 \(G\) ,其中如果 \((u, v)\) 在 \(G_1\) 与 \(G_2\) 中的出现次数之和为 \(1 ...