❶ 高分:网络流问题
一、引言
网络流算法是一种高效实用的算法,相对于其它图论算法来说,它的模型更加复杂,编程复杂度也更高。但是它综合了图论中的其它一些算法(如最短路径、宽度搜索算法),因而适用范围也更广,经常能够很好地解决一些搜索与动态规划无法解决的非np问题。
网络流在具体问题中的应用,最具挑战性的部分是模型的构造,它没用现成的模式可以套用,需要我们对各种网络流的性质了如指掌(比如点有容量、容量有上下限、多重边等等),根据具体的问题发挥我们的创造性。一道问题经常可以建立多种模型,不同的模型对问题的解决效率的影响也是不同的,本文通过实例探讨如何确定适当的模型,提高网络流算法的效率。
二、网络流算法时间效率
当我们确定问题可以使用最大流算法求解后,就根据常用的ford-fulkerson标号法求解;而最小(大)费用最大流问题也可用类似标号法的对偶算法解题。ford-fulkerson标号法的运行时间为o(ve2),对偶法求最小费用流的运行时间大约为o(v3e2)。
显然,影响网络流算法的时间效率的因素主要是网络中顶点的数目与边的数目。这二个因素之间不是相互独立的,而是相互联系,矛盾而统一的。在构造网络模型中,有时,实现了某个因素的优化,另外一个因素也随之得到了优化;有时,实现某个因素的优化却要以增大另一因素为代价。因此,我们在具体问题的解决中,要坚持"全局观",实现二者的平衡。
三、模型的优化与选择
(一)减少模型的顶点数与边数,优化模型
如果能根据问题的一些特殊性质,减少网络模型中的顶点的数目和边的数目,则可以大大提高算法的效率。
例1:最少皇后控制
在国际象棋中,皇后能向八个方向攻击(如图1(a)所示,图中黑点格子为皇后的位置,标有k的格子为皇后可攻击到的格子)。现在给定一个m*n(n、m均不大于于50)的棋盘,棋盘上某些格子有障碍。每个皇后被放置在无障碍的格子中,它就控制了这个格子,除此,它可以从它能攻击到的最多8个格子中选一个格子来控制,如图1(b)所示,标号为1的格子被一个皇后所控制。
请你编一程序,计算出至少有多少个皇后才能完全控制整个棋盘。
图1(a) 图1(b)
输入格式:
输入文件的第一行有两个整数m和n,表示棋盘的行数与列数。接下来m行n列为一个字符矩阵,用''.''号表示空白的格子,''x''表示有障碍的格子。
输出格式:
输出文件的第一行仅有一个数s,表示需要皇后的数目。
sample input
3 4
x...
x.x.
.x..
sample ouput
5
问题分析]
如果本问题用简单的搜索来做,由于题目给的棋盘很大,搜索算法很难在短时间内出解。由于一个皇后在棋盘最多只能控制两个格子,因此最少需要的皇后数目的下界为[n*m/2]。要使得皇后数目最少,必定是尽量多的皇后控制两个格子。如果我们在每两个能相互攻击到的格子之间加上一条有向弧,则问题很类似于二分图的最大匹配问题。
[模型一]
1. 将每个非障碍的格子按行优先编号(0~m*n-1)。
2. 将上述的每个格子i折成两个格子i''和i'''',作为网络模型中的顶点。
3. 若格子i可以攻击到格子j且i<j,则在模型中顶点i''到j''''之间加上一条有向弧,容量为1。
4. 增加一个源点s,从s点向所有顶点i''添上一条弧;增加一个汇点t,从所有顶点j''''到t添上一条弧,容量均为1。
图1(b)所示的棋盘,对应的模型为:
图2
显然,任一解对应于以上模型的一个最大匹配。且最大匹配中,匹配数必定是偶数。因此至少需要的马匹数为m*n-障碍数-最大匹配数/2。
[模型二]
如果我们将棋盘涂成黑白相间的格子,则某皇后控制的两个格子一定是一个是黑格,另一个是白格(如图3),不妨设这两个格子中皇后在白格子上。于是,我们将n*m个格子分成两部分白格与黑格。因此我们可以将模型一优化为:
图3
1.将棋盘中的所有格子分成两个部分,对所有的格子进行编号,每个白格与它能攻击到的黑格之间(障碍除外)添上一条从白格到黑格的弧,构成一个二分图。
2.增加一个源点s,从s点向所有非障碍的白格添上一条弧;增加一个汇点t,从所有非障碍的黑格到t添上一条弧。
3.设置所有的弧的流量为1。
图1(b)所示的棋盘,对应的模型为:
图4
[两种模型的比较]
显然,模型二的顶点数与边数大致是模型一的一半。下面是在bp环境下两种模型的时间效率比较(p166/32m):
模型一 模型二
可扩展性 不易打印出一种解 容易打印出一种解
模型二正是根据问题的特殊性(即马的走法),将网格中的格点分成白与黑两类,且规定马只能从白格跳到黑格,从而避免将每个格点折分成两个点,减少模型的顶点数,同时也大大减少了边的数目。达到了很好的优化效果。
(二)综合各种模型的优点,智能选择模型
有时,同一问题的各种模型各有特色,各有利弊。这种情况下,我们就要综合考虑各种模型的优缺点,根据测试数据智能地选择问题的模型。
例2火星探测器(ioi97)
有一个登陆舱(pod),里边装有许多障碍物探测车(mev),将在火星表面着陆。着陆后,探测车离开登陆舱向相距不远的先期到达的传送器(transmitter)移动,mev一边移动,一边采集岩石(rock)标品,岩石由第一个访问到它的mev所采集,每块岩石只能被采集一次。但是这之后,其他mev可以从该处通过。探测车mev不能通过有障碍的地面。
本题限定探测车mev只能沿着格子向南或向东从登陆处向传送器transmitter移动,允许多个探测车mev在同一时间占据同一位置。
任务:计算出所有探测车的移动途径,使其送到传送器的岩石标本的数量最多,且使得所有的探测车都必须到达传送器。
输入:
火星表面上的登陆舱pod和传送器之间的位置用网络p和q表示,登陆舱pod的位置为(1,1)点,传送器的位置在(p,q)点。
火星上的不同表面用三种不同的数字符号来表示:
0代表平坦无障碍
1代表障碍
2代表石块。
输入文件的组成如下:
numberofvehicles
p
q
(x1y1)(x2y1)(x3,y1)…(xp-1y1)(xpy1)
(x1y2)(x2y2)(x3,y2)…(xp-1y1)(xpy2)
(x1y3)(x2y3)(x3,y3)…(xp-1y3)(xpy3)
…
(x1yq-1)(x2yq-1)(x3,yq-1)…(xp-1yq-1)(xpyq-1)
(x1yq)(x2yq)(x3,yq)…(xp-1yq)(xpyq)
p和q是网络的大小;numberofvehicles是小于1000的整数,表示由登陆舱pod所开出的探测车的个数。共有q行数据,每行表示火星表面的一组数据,p和q都不超过128。
[模型一]
很自然我们以登陆舱的位置为源点,传送器的位置为汇点。同时某块岩石由第一个访问到它的mev所采集,每块岩石只能被采集一次。但是这之后,其他mev可以从该处通过,且允许多个探测车mev在同一时间占据同一位置。因此我们将地图中的每个点分成两个点,即(x,y)à(x,y,0)和(x,y,1)。具体的描述一个火星地图的网络模型构造如下:
1. 将网格中的每个非障碍点分成(x,y)两个点(x,y,0)和(x,y,1),其中源点s = v(1, 1, 0),汇点t = v(maxx, maxy, 1)。
2. 在以上顶点中添加以下三种类型的边e1,e2,e3,相应地容量和费用分别记为c1、c2、c3以及w1、w2、w3:
u e1 = v(x, y, 0) -> v(x, y, 1),c1 = maxint,w1 = 0。
u e2 = v(x, y, 0) -> v(x, y, 1),c2 = 1,w2 = -1(这里要求(x, y)必须是矿石)
u e3 = v(x, y, 1) -> v(x'', y'', 0),c3 = maxint,w3 = 0.
其中x''=x+1 y''=y 或x''=x y''=y+1,1 <= x'' <= maxx,1 <= y'' <= maxy,且(x'' y'')非障碍。
从以上模型中可以看出,在构造的过程中,将地图上的一个点"拆"成了网络的两个节点。添加e1型边使得每个点可以被多次访问,而添加e2型边使得某点上的矿石对于这个网络,从s到t的一条路径可以看作是一辆探测车的行动路线。路径费用就是探测车搜集到的矿石的数目。对于网络g求流量为numberofvehicles的固定最小费用流,可以得到问题的解。
[模型二]
事实上,如果我们只考虑这numberofvehicles辆车中每辆车分别依次装上哪些矿石。则每辆车经过的矿石就是一条流,因此我们以网格中的矿石为网络的顶点建立以下的网络流模型。
1. 将网格中的每个起点(网格左上角)能到达,且能从它能到达终点(右下角)的矿石 (x,y)点分成左点(x,y,0)和右点(x,y,1)两个点,并添加源点s和汇点t。
2. 在以上顶点中添加以下五种类型的边e1,e2,e3,相应地容量和费用分别记为c1、c2、c3以及w1、w2、w3:
u e1 = v(x, y, 0) -> v(x, y, 1),c1 = 1,w1 = -1。
u e2 = v(x, y, 1) -> v(x'', y'', 0),c2 = 1,w2 = 0(矿石点(x, y)可到达矿石点(x'',y''))。
u e3 = s -> v(x, y, 0),c3 = 1,w3 = 0。
u e4 = v(x, y, 1)->t,c4 = 1,w4 = 0。
u e5=s->t,c5=maxint,w5=0。
由于每个石块被折成两个点,且容量为1,就保证了每个石块只被取走一次,同时取走一块石块就得到-1的费用。因此对以上模型,我们求流量为numberofvehicles的最小费用流,就可得到解。
[两种模型的比较]
1.模型一以网格为顶点,模型二以矿石为顶点,因此在顶点个数上模型二明显优于模型一,对于一些矿石比较稀疏,而网格又比较大的数据,模型二的效率要比模型一来得高。且只要矿石的个数不超过一定数目,模型二可以处理p,q很大的数据,而模型一却不行。
2.模型一中边的数目最多为3*p*q,而模型二中边的数目最坏情况下大约为p*q*(p+1)*(q+1)/4-p*q。因此在这个问题中,若对于一些矿石比较密集且网格又比较大的数据,模型二的边数将大大超过模型一,从而使得时间效率大大低于模型一。
下面是网格中都是矿石的情况比较(piii700/128m ,bp7.0保护模式):
numberofvehicles=10 模型一 模型二
通过以上数据,可知对于p,q不超过60的情况,模型一都能在10秒内出解。而模型二则对于p、q=30的最坏情况下速度就很慢了,且p、q超过30后就出现内存溢出情况,而无法解决。
因此,对于本题,以上两种模型各有利弊,我们可根据测试数据中矿石稀疏程度来决定建立什么样的模型。若矿石比较稀疏,则可以考虑用建立如模型二的网络模型;若矿石比较密集则建立模型一所示网络模型。然后,再应用求最小费用最大流算法求解。对于p,q>60,且矿石比较多情况下,两种模型的网络流算法都无法求解。在实际的应用中问题经常都只要求近似解,此时还可用综合一些其它算法来求解。
四、结束语
综上所述,网络流算法中模型的优化是网络流算法提高效率的根本。我们要根据实际问题,从减少顶点及边的角度综合考虑如何对模型进行优化,选择适当的模型,以提高算法的效率。对于有些题目,解题的各种模型各有优劣时,还可通过程序自动分析测试数据,以决定何种情况下采用何种模型,充分发挥各种模型的优点,以达到优化程序效率的目的。
❷ potplayer 怎么播放网络流
PotPlayer播放器程序的获取:直接在网络中搜索“PotPlayer”即可从搜索结果中获取对应程序的下载地址。如图所示:
播放视频的方法:右击播放器窗口,从弹出的右键菜单中依次选择“打开”项,此时将展开“打开”子菜单项,从中选择相应的子项即可实现视频的播放操作。
如图所示,当我们选择“打开链接”项时,将弹出如图所示的窗口,在此直接粘贴要播放的视频文件地址,点击“确定”即可进行在线视频观看操作。
高级设置菜单:右击播放器界面,从弹出的菜单中选择“选择”项,就可以打开“高级选项”菜单。
播放器皮肤的更改:右击播放器窗口,在弹出的扩展菜单中选择“皮肤”项,就可以从其扩展面板中使用其它皮肤啦。
播放列表的开启:右击播放器右下角的“打开/隐藏播放列表”按钮,就可以开启或隐藏播放列表啦。
❸ 直播-拉流和推流怎么设置
直播-拉流和推流首先要了解拉流和推流的原理。
直播中视频编码器可以称为推流,就是把前端的视频画面通过编码器推流到各个直播平台。
推流中只要将直播平台的推流地址复制到编码器管理后台即可实现推流操作。比方说RTSP,RTMP推流等。
视频解码器可以称为拉流,就是把你网络的视频流通过解码器拉流还原到大屏上显示,显示包括电视、拼接屏等。如果需要把视频还原在大屏幕显示出来,就需要解码器。设置跟编码器同样道理。
直播编解码器原理图
❹ MX播放器里的网络流怎么用
MX video player支持网络流媒体播放,打开播放器,在网络流里面输入目标视频的URL即可,需要配合3G或者无线网络进行。以前人们在网络上观看电影或收听音乐时,必须先将整个影音文件下载并存储在本地计算机上,然后才可以观看。与传统的播放方式不同,流媒体在播放前并不下载整个文件,只将部分内容缓存,使流媒体数据流边传送边播放,这样就节省了下载等待时间和存储空间。
❺ C++网络流 残量网络是什么意思 传递闭包是什么意思,怎么求
求网络流有很多算法,这几天学习了两种,记录一下EK算法。
首先是网络流中的一些定义:
V表示整个图中的所有结点的集合.
E表示整个图中所有边的集合.
G = (V,E) ,表示整个图.
s表示网络的源点,t表示网络的汇点.
对于每条边(u,v),有一个容量c(u,v) (c(u,v)>=0),如果c(u,v)=0,则表示(u,v)不存在在网络中。相反,如果原网络中不存在边(u,v),则令c(u,v)=0.
对于每条边(u,v),有一个流量f(u,v).
一个简单的例子.网络可以被想象成一些输水的管道.括号内右边的数字表示管道的容量c,左边的数字表示这条管道的当前流量f.
网络流的三个性质:
1、容量限制: f[u,v]<=c[u,v]
2、反对称性:f[u,v] = - f[v,u]
3、流量平衡: 对于不是源点也不是汇点的任意结点,流入该结点的流量和等于流出该结点的流量和。
只要满足这三个性质,就是一个合法的网络流.
最大流问题,就是求在满足网络流性质的情况下,源点 s 到汇点 t 的最大流量。
求一个网络流的最大流有很多算法 这里首先介绍 增广路算法(EK)
学习算法之前首先看了解这个算法中涉及到的几个图中的定义:
**残量网络
为了更方便算法的实现,一般根据原网络定义一个残量网络。其中r(u,v)为残量网络的容量。
r(u,v) = c(u,v) – f(u,v)
通俗地讲:就是对于某一条边(也称弧),还能再有多少流量经过。
Gf 残量网络,Ef 表示残量网络的边集.
这是上面图的一个残量网络。残量网络(如果网络中一条边的容量为0,则认为这条边不在残量网络中。
r(s,v1)=0,所以就不画出来了。另外举个例子:r(v1,s) = c(v1,s) – f(v1,s) = 0 – (-f(s,v1)) = f(s,v1) = 4.
其中像(v1,s)这样的边称为后向弧,它表示从v1到s还可以增加4单位的流量。
但是从v1到s不是和原网络中的弧的方向相反吗?显然“从v1到s还可以增加4单位流量”这条信息毫无意义。那么,有必要建立这些后向弧吗?
显然,第1个图中的画出来的不是一个最大流。
但是,如果我们把s -> v2 -> v1 -> t这条路径经过的弧的流量都增加2,就得到了该网络的最大流。
注意到这条路径经过了一条后向弧:(v2,v1)。
如果不设立后向弧,算法就不能发现这条路径。
**从本质上说,后向弧为算法纠正自己所犯的错误提供了可能性,它允许算法取消先前的错误的行为(让2单位的流从v1流到v2)
注意,后向弧只是概念上的,在程序中后向弧与前向弧并无区别.
**增广路
增广路定义:在残量网络中的一条从s通往t的路径,其中任意一条弧(u,v),都有r[u,v]>0。
如图绿色的即为一条增广路。
看了这么多概念相信大家对增广路算法已经有大概的思路了吧。
**增广路算法
增广路算法:每次用BFS找一条最短的增广路径,然后沿着这条路径修改流量值(实际修改的是残量网络的边权)。当没有增广路时,算法停止,此时的流就是最大流。
**增广路算法的效率
设n = |V|, m = |E|
每次增广都是一次BFS,效率为O(m),而在最坏的情况下需要(n-2增广。(即除源点和汇点外其他点都没有连通,所有点都只和s与t连通)
所以,总共的时间复杂度为O(m*n),所以在稀疏图中效率还是比较高的。
❻ ffmpeg怎么样处理网络流
#include"utils.h"
#include<pthread.h>
#include<libavcodec/avcodec.h>
#include<libavformat/avformat.h>
UdpQueuerecvqueue;
UdpParamudpParam;
//注册av_read_frame的回调函数,这里只是最简处理,实际应用中应加上出错处理,超时等待...
intread_data(void*opaque,uint8_t*buf,intbuf_size){
intsize=buf_size;
intret;
//printf("readdata%d ",buf_size);
do{
ret=get_queue(&recvqueue,buf,buf_size);
}while(ret);
//printf("readdataOk%d ",buf_size);
returnsize;
}
#defineBUF_SIZE4096*500
intmain(intargc,char**argv){
init_queue(&recvqueue,1024*500);
udpParam.argv=argv;
udpParam.queue=&recvqueue;
uint8_t*buf=av_mallocz(sizeof(uint8_t)*BUF_SIZE);
//UDP接收线程
pthread_tudp_recv_thread;
pthread_create(&udp_recv_thread,NULL,udp_ts_recv,&udpParam);
pthread_detach(udp_recv_thread);
av_register_all();
AVCodec*pVideoCodec,*pAudioCodec;
AVCodecContext*pVideoCodecCtx=NULL;
AVCodecContext*pAudioCodecCtx=NULL;
AVIOContext*pb=NULL;
AVInputFormat*piFmt=NULL;
AVFormatContext*pFmt=NULL;
//step1:申请一个AVIOContext
pb=avio_alloc_context(buf,BUF_SIZE,0,NULL,read_data,NULL,NULL);
if(!pb){
fprintf(stderr,"avioallocfailed! ");
return-1;
}
//step2:探测流格式
if(av_probe_input_buffer(pb,&piFmt,"",NULL,0,0)<0){
fprintf(stderr,"probefailed! ");
return-1;
}else{
fprintf(stdout,"probesuccess! ");
fprintf(stdout,"format:%s[%s] ",piFmt->name,piFmt->long_name);
}
pFmt=avformat_alloc_context();
pFmt->pb=pb;//step3:这一步很关键
//step4:打开流
if(avformat_open_input(&pFmt,"",piFmt,NULL)<0){
fprintf(stderr,"avformatopenfailed. ");
return-1;
}else{
fprintf(stdout,"openstreamsuccess! ");
}
//以下就和文件处理一致了
if(av_find_stream_info(pFmt)<0){
fprintf(stderr,"couldnotfinestream. ");
return-1;
}
av_mp_format(pFmt,0,"",0);
intvideoindex=-1;
intaudioindex=-1;
for(inti=0;i<pFmt->nb_streams;i++){
if((pFmt->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)&&
(videoindex<0)){
videoindex=i;
}
if((pFmt->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO)&&
(audioindex<0)){
audioindex=i;
}
}
if(videoindex<0||audioindex<0){
fprintf(stderr,"videoindex=%d,audioindex=%d ",videoindex,audioindex);
return-1;
}
AVStream*pVst,*pAst;
pVst=pFmt->streams[videoindex];
pAst=pFmt->streams[audioindex];
pVideoCodecCtx=pVst->codec;
pAudioCodecCtx=pAst->codec;
pVideoCodec=avcodec_find_decoder(pVideoCodecCtx->codec_id);
if(!pVideoCodec){
fprintf(stderr,"couldnotfindvideodecoder! ");
return-1;
}
if(avcodec_open(pVideoCodecCtx,pVideoCodec)<0){
fprintf(stderr,"couldnotopenvideocodec! ");
return-1;
}
pAudioCodec=avcodec_find_decoder(pAudioCodecCtx->codec_id);
if(!pAudioCodec){
fprintf(stderr,"couldnotfindaudiodecoder! ");
return-1;
}
if(avcodec_open(pAudioCodecCtx,pAudioCodec)<0){
fprintf(stderr,"couldnotopenaudiocodec! ");
return-1;
}
intgot_picture;
uint8_tsamples[AVCODEC_MAX_AUDIO_FRAME_SIZE*3/2];
AVFrame*pframe=avcodec_alloc_frame();
AVPacketpkt;
av_init_packet(&pkt);
while(1){
if(av_read_frame(pFmt,&pkt)>=0){
if(pkt.stream_index==videoindex){
fprintf(stdout,"pkt.size=%d,pkt.pts=%lld,pkt.data=0x%x.",pkt.size,pkt.pts,(unsignedint)pkt.data);
avcodec_decode_video2(pVideoCodecCtx,pframe,&got_picture,&pkt);
if(got_picture){
fprintf(stdout,"decodeonevideoframe! ");
}
}elseif(pkt.stream_index==audioindex){
intframe_size=AVCODEC_MAX_AUDIO_FRAME_SIZE*3/2;
if(avcodec_decode_audio3(pAudioCodecCtx,(int16_t*)samples,&frame_size,&pkt)>=0){
fprintf(stdout,"decodeoneaudioframe! ");
}
}
av_free_packet(&pkt);
}
}
av_free(buf);
av_free(pframe);
free_queue(&recvqueue);
return0;
}
❼ 手机影音先锋怎么打开网络流
网络流(network-flows)是一种类比水流的解决问题方法,与线性规划密切相关。网络流的理论和应用在不断发展,出现了具有增益的流、多终端流、多商品流以及网络流的分解与合成等新课题。网络流的应用已遍及通讯、运输、电力、工程规划、任务分派、设备更新以及计算机辅助设计等众多领域。
影音先锋怎么用?影音先锋xfplay怎么用呢?影音先锋xfplay的使用方法,小编这就为大家介绍,亲自体验介绍影音先锋xfplay怎么用!为你展示影音先锋xfplay的使用方法,瞬间知晓影音先锋xfplay怎么用。
首先下载影音先锋,你可以在本页面下面下载影音先锋,也可以访问网络首页,在网络搜索“影音先锋”,点击“网络一下”,然后进入影音先锋的官方网站。
点击“影音先锋晕3D版下载”按钮开始下载影音先锋。下载完成后,双击启动安装程序,开始在电脑中安装影音先锋,等待程序安装完成。
安装完成后启动影音先锋,在影音先锋文件的播放界面右键单击,在出现的右键菜单列表中选择“打开文件”选项,然后在弹出的对话框中,选择视频文件,点击“打开”按钮开始播放。
除此之外,您还可以打开其他文件类型,比如种子文件,mp3格式的文件,DVD光盘等。影音先锋还有更多的使用方法等待您去体验。
有一个方法很实用,就是下载网络电影。打开一个可以使用影音先锋播放的电影网站,然后打开一个电影播放页面,
在网页界面右键单击播放器,然后在出现的右键菜单列表中选择“使用先锋播放...”选择,就可以打开电脑中的影音先锋播放器,使用该软件下载或播放了。