The least round way

本文详细解析了在方阵中寻找最小回合方式的问题,即在矩阵中从左上角到右下角,使得路径上数字乘积尾数含0最少的路径。文章介绍了算法思路,包括如何处理路径上可能存在的0、2和5因子,以及如何递归输出最优路径。

B. The least round way
time limit per test2 seconds
memory limit per test64 megabytes
inputstandard input
outputstandard output
There is a square matrix n × n, consisting of non-negative integer numbers. You should find such a way on it that

starts in the upper left cell of the matrix;
each following cell is to the right or down from the current cell;
the way ends in the bottom right cell.
Moreover, if we multiply together all the numbers along the way, the result should be the least “round”. In other words, it should end in the least possible number of zeros.

Input
The first line contains an integer number n (2 ≤ n ≤ 1000), n is the size of the matrix. Then follow n lines containing the matrix elements (non-negative integer numbers not exceeding 109).

Output
In the first line print the least number of trailing zeros. In the second line print the correspondent way itself.

中文

B.最小回合方式
每次测试的时限2秒
每次测试的内存限制64兆字节
输入标准输入
输出标准输出
有一个由非负整数组成的方阵n  ×  n。您应该在上面找到这样的方法

从矩阵的左上角单元格开始;
接下来的每个单元格都位于当前单元格的右侧或下方;
方式在右下角的单元格中结束。
此外,如果我们将所有数字相乘,结果应该是最小的“舍入”。换句话说,它应以尽可能少的零结尾。

输入项
第一行包含的整数Ñ(2≤  Ñ  ≤1000),Ñ是矩阵的大小。然后跟随n行包含矩阵元素(不超过10 9的非负整数)。

输出量
在第一行中,打印最少数量的尾随零。在第二行中打印相应的方式本身。

例子
输入项复制
3
1 2 3
4 5 6
7 8 9
输出量复制
0
DDRR

两个要求, 第一个就是所走路径上的数字乘起来,0的个数最小, 第二个就是输出的时候要输出一下路径, 参考网上的题解, 若是没有0的个数最小,那么就是一个简单的dp。 而加上这个条件之后, 乘积带0的, 考虑三种情况, 1:路径中含有0 , 那么必然要走这样的,因为此时只有1个零, 最小无疑, 2:路径中含有因子2 ,3 : 路径因子中含有5的个数,因为这两种情况才有可能使乘积构成0, 那么就再考虑一下这两种情况, 其实只单看一种情况就行了, 因为如果两个合起来, 更容易产生尾数含有0的,2 * 5 = 10 , 只需两个因子, 而只考虑含有因子2, 或因子5 , 每一个都非常难以构成一个带0的数, 但是有可能考虑每个因子的时候呢 , 该数同时含有2 和 5 , 所以这种情况我们只需要2 和 5 因子的个数最小就行 , 然后选择路径的时候, 还是三种情况, 若路径中含有0 , 必定选择, 设0的坐标为(x , y) , 那么只需要写成DDDRRRR或者RRRDDDDD 就行了, 然后如果是选择因子2或因子5的那一条,只需看最小值等于哪一种就行了, 然后就递归输出

#include <iostream>
#include <cstring>
using namespace std;
const int N = 1005 ;
int n , ans , x , y , a[N][N] , f[N][N] , g[N][N] ; 
bool zero = 0 ; 
void go(int x , int y , int p , int q)
{
	while(x != p) printf("D") , ++ x ;
	while(y != q) printf("R") , ++ y ;
}
void walk(int h[N][N] , int x , int y)
{
	if(x == 1 && y == 1) return ; 
	if(h[x - 1][y] < h[x][y - 1]) walk(h , x - 1 , y) , printf("D") ;
    else walk(h , x , y - 1) , printf("R") ; 
}
int main() 
{ 
	memset(f , 60 , sizeof f) ;
	memset(g , 60 , sizeof g) ;
	f[0][1] = g[0][1] = 0 ;
	scanf("%d" , &n) ;
	for(int i = 1 ;i <= n ;i ++)
	 for(int j = 1 ;j <= n ;j ++)
	  {
	  	int u = 0 , v = 0 ;
	  	scanf("%d" , &a[i][j]) ;
	  	if(!a[i][j]) zero = 1 , x = i , y = j ;
	  	if(!a[i][j]) continue ;
	  	while(a[i][j] % 2 == 0) a[i][j] /= 2 , ++ u ;
	  	while(a[i][j] % 5 == 0) a[i][j] /= 5 , ++ v ;
	  	f[i][j] = min(f[i][j - 1] , f[i - 1][j]) + u ;
	  	g[i][j] = min(g[i][j - 1] , g[i - 1][j]) + v ;
	  }
	  ans = min(f[n][n] , g[n][n]) ;
	  if(zero) ans = min(ans , 1 ) ;
	  printf("%d\n" , ans) ;
	  if(ans == f[n][n]) walk(f , n , n) ;
	  else if(ans == g[n][n]) walk(g , n , n) ;
	  else
	   {
	   	  go(1 , 1, x , y ) ;
	   	  go(x , y, n , n ) ;
       }
	return 0 ;
}
<!-- go/cmark --> <!--* freshness: {owner: 'sprang' reviewed: '2021-04-12'} *--> # Paced Sending The paced sender, often referred to as just the "pacer", is a part of the WebRTC RTP stack used primarily to smooth the flow of packets sent onto the network. ## Background Consider a video stream at 5Mbps and 30fps. This would in an ideal world result in each frame being ~21kB large and packetized into 18 RTP packets. While the average bitrate over say a one second sliding window would be a correct 5Mbps, on a shorter time scale it can be seen as a burst of 167Mbps every 33ms, each followed by a 32ms silent period. Further, it is quite common that video encoders overshoot the target frame size in case of sudden movement especially dealing with screensharing. Frames being 10x or even 100x larger than the ideal size is an all too real scenario. These packet bursts can cause several issues, such as congesting networks and causing buffer bloat or even packet loss. Most sessions have more than one media stream, e.g. a video and an audio track. If you put a frame on the wire in one go, and those packets take 100ms to reach the other side - that means you have now blocked any audio packets from reaching the remote end in time as well. The paced sender solves this by having a buffer in which media is queued, and then using a _leaky bucket_ algorithm to pace them onto the network. The buffer contains separate fifo streams for all media tracks so that e.g. audio can be prioritized over video - and equal prio streams can be sent in a round-robin fashion to avoid any one stream blocking others. Since the pacer is in control of the bitrate sent on the wire, it is also used to generate padding in cases where a minimum send rate is required - and to generate packet trains if bitrate probing is used. ## Life of a Packet The typical path for media packets when using the paced sender looks something like this: 1. `RTPSenderVideo` or `RTPSenderAudio` packetizes media into RTP packets. 2. The packets are sent to the [RTPSender] class for transmission. 3. The pacer is called via [RtpPacketSender] interface to enqueue the packet batch. 4. The packets are put into a queue within the pacer awaiting opportune moments to send them. 5. At a calculated time, the pacer calls the `PacingController::PacketSender()` callback method, normally implemented by the [PacketRouter] class. 6. The router forwards the packet to the correct RTP module based on the packet's SSRC, and in which the `RTPSenderEgress` class makes final time stamping, potentially records it for retransmissions etc. 7. The packet is sent to the low-level `Transport` interface, after which it is now out of scope. Asynchronously to this, the estimated available send bandwidth is determined - and the target send rate is set on the `RtpPacketPacer` via the `void SetPacingRates(DataRate pacing_rate, DataRate padding_rate)` method. ## Packet Prioritization The pacer prioritized packets based on two criteria: * Packet type, with most to least prioritized: 1. Audio 2. Retransmissions 3. Video and FEC 4. Padding * Enqueue order The enqueue order is enforced on a per stream (SSRC) basis. Given equal priority, the [RoundRobinPacketQueue] alternates between media streams to ensure no stream needlessly blocks others. ## Implementations The main class to use is called [TaskQueuePacedSender]. It uses a task queue to manage thread safety and schedule delayed tasks, but delegates most of the actual work to the `PacingController` class. This way, it's possible to develop a custom pacer with different scheduling mechanism - but ratain the same pacing logic. ## The Packet Router An adjacent component called [PacketRouter] is used to route packets coming out of the pacer and into the correct RTP module. It has the following functions: * The `SendPacket` method looks up an RTP module with an SSRC corresponding to the packet for further routing to the network. * If send-side bandwidth estimation is used, it populates the transport-wide sequence number extension. * Generate padding. Modules supporting payload-based padding are prioritized, with the last module to have sent media always being the first choice. * Returns any generated FEC after having sent media. * Forwards REMB and/or TransportFeedback messages to suitable RTP modules. At present the FEC is generated on a per SSRC basis, so is always returned from an RTP module after sending media. Hopefully one day we will support covering multiple streams with a single FlexFEC stream - and the packet router is the likely place for that FEC generator to live. It may even be used for FEC padding as an alternative to RTX. ## The API The section outlines the classes and methods relevant to a few different use cases of the pacer. ### Packet sending For sending packets, use `RtpPacketSender::EnqueuePackets(std::vector<std::unique_ptr<RtpPacketToSend>> packets)` The pacer takes a `PacingController::PacketSender` as constructor argument, this callback is used when it's time to actually send packets. ### Send rates To control the send rate, use `void SetPacingRates(DataRate pacing_rate, DataRate padding_rate)` If the packet queue becomes empty and the send rate drops below `padding_rate`, the pacer will request padding packets from the `PacketRouter`. In order to completely suspend/resume sending data (e.g. due to network availability), use the `Pause()` and `Resume()` methods. The specified pacing rate may be overriden in some cases, e.g. due to extreme encoder overshoot. Use `void SetQueueTimeLimit(TimeDelta limit)` to specify the longest time you want packets to spend waiting in the pacer queue (pausing excluded). The actual send rate may then be increased past the pacing_rate to try to make the _average_ queue time less than that requested limit. The rationale for this is that if the send queue is say longer than three seconds, it's better to risk packet loss and then try to recover using a key-frame rather than cause severe delays. ### Bandwidth estimation If the bandwidth estimator supports bandwidth probing, it may request a cluster of packets to be sent at a specified rate in order to gauge if this causes increased delay/loss on the network. Use the `void CreateProbeCluster(...)` method - packets sent via this `PacketRouter` will be marked with the corresponding cluster_id in the attached `PacedPacketInfo` struct. If congestion window pushback is used, the state can be updated using `SetCongestionWindow()` and `UpdateOutstandingData()`. A few more methods control how we pace: * `SetAccountForAudioPackets()` determines if audio packets count into bandwidth consumed. * `SetIncludeOverhead()` determines if the entire RTP packet size counts into bandwidth used (otherwise just media payload). * `SetTransportOverhead()` sets an additional data size consumed per packet, representing e.g. UDP/IP headers. ### Stats Several methods are used to gather statistics in pacer state: * `OldestPacketWaitTime()` time since the oldest packet in the queue was added. * `QueueSizeData()` total bytes currently in the queue. * `FirstSentPacketTime()` absolute time the first packet was sent. * `ExpectedQueueTime()` total bytes in the queue divided by the send rate. [RTPSender]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/rtp_rtcp/source/rtp_sender.h;drc=77ee8542dd35d5143b5788ddf47fb7cdb96eb08e [RtpPacketSender]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/api/rtp_packet_sender.h;drc=ea55b0872f14faab23a4e5dbcb6956369c8ed5dc [RtpPacketPacer]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/pacing/rtp_packet_pacer.h;drc=e7bc3a347760023dd4840cf6ebdd1e6c8592f4d7 [PacketRouter]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/pacing/packet_router.h;drc=3d2210876e31d0bb5c7de88b27fd02ceb1f4e03e [TaskQueuePacedSender]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/pacing/task_queue_paced_sender.h;drc=5051693ada61bc7b78855c6fb3fa87a0394fa813 [RoundRobinPacketQueue]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/pacing/round_robin_packet_queue.h;drc=b571ff48f8fe07678da5a854cd6c3f5dde02855f 翻译
最新发布
12-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值